• 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));
    } 
    

      

  • 相关阅读:
    [转贴] IPSEC From 知乎
    intel 的架构图
    IPV6 简单验证
    exsi6.0远程修改密码
    Oracle单个datafile大小的限制
    用Linux完成Oracle自动物理备份
    vSphere Client 更改 ESX/ESXi 主机的端口
    netstat Recv-Q和Send-Q
    Linux下安装(卸载)KDE和GNOME
    完美解决xhost +报错: unable to open display ""
  • 原文地址:https://www.cnblogs.com/pkgunboat/p/10827925.html
Copyright © 2020-2023  润新知