GYM 101933E 状态压缩 + 记忆化搜索

题意:我方有n个士兵,敌方有m个,每方士兵都有一个血量,现在有k轮无差别炮火打击,每次都会从存活的士兵中随机选一人,这名士兵的HP就-1,问对方被团灭的概率有多大?

思路:因为n和m的范围很小,我们可以考虑暴力搜索,中间使用记忆化。这里状态压缩有一个小技巧,我们的正常想法是:因为士兵总数最多只有10个,我们可以用一个十位数来表示状态,每一位数代表这个士兵的现在的HP。但是我这样设计状态超时了。。。网上的状态设置的比较巧妙,网上用了12位数来表示状态,每一位代表敌方或者我方的HP为某个值的士兵还剩多少个。这样设计状态的好处在于如果有多个士兵的HP相同,那么只需向下搜索一个就行了,大大减少了搜索的分支。

代码:

#include <bits/stdc++.h>
#define LL long long
#define db double
using namespace std;
map<LL, db> dp;
int now_state[2][7];
int n, m;
LL limit;
LL get_state(void) {
	LL state = 0;
	for (int i = 1; i <= 6; i++)
		state = state * 10 + now_state[1][i];
	for (int i = 1; i <= 6; i++)
		state = state * 10 + now_state[0][i];
	return state;
}
db dfs(LL state, int deep) {
	if(dp.count(state)) return dp[state];
	if(state < 1000000) return 1;
	if(deep == 0) return 0;
	int cnt = 0;
	db ans = 0;
	for (int i = 0; i <= 1; i++)
		for (int j = 1; j <= 6; j++)
			cnt += now_state[i][j];
	for (int i = 0 ; i <= 1; i++)
		for (int j = 1; j <= 6; j++) {
			if(!now_state[i][j]) continue;
			now_state[i][j]--;
			now_state[i][j - 1]++;
			ans += dfs(get_state(), deep - 1) * (now_state[i][j] + 1) / (db) cnt;
			now_state[i][j]++;
			now_state[i][j - 1]--;
		}
	dp[state] = ans;
	return ans;
} 
int main() {
	int k, x; 
	scanf("%d%d%d", &n, &m, &k);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &x);
		now_state[0][x]++;
	}
	for (int i = 1; i <= m; i++) {
		scanf("%d", &x);
		now_state[1][x]++;
	}
	printf("%.7lf
", dfs(get_state(), k));
} 

  

原文地址:https://www.cnblogs.com/pkgunboat/p/10827925.html