zoukankan      html  css  js  c++  java
  • 2011 ACM-ICPC 成都赛区A题 Alice and Bob (博弈动规)

    题目大意:

           有K堆石子,每堆有Ki个。两人的操作能够是:
                1 从某一堆拿走一个 假设该堆在此之后没有石子了。就消失
                2 合并两个堆
           求是否先手必胜,先手胜输出Alice。否则输出Bob


    思路:

           这道题读完后毫无头绪。推了半天也推不个所以然来,參看大神代码后,感觉就是一个记忆化搜索啊,唉,知识学多了不会用还是白搭。还得多做题啊!

           这里我们把数字分成 1,2,大于等于3的奇数,大于等于4的偶数四类。
           这样分的原因在于。一个大于3的奇数是实际上等价于3的;由于每当对手减一个。自己也减一个。就又变回了一个大于3的奇数。终于变成3。

    同理。全部大于2的偶数等价于4。
           所以我们用dp[a][b][c][d]表示有a个1,b个2,c个3,d个4是不是一个必胜态,然后动规求解就好了。


    代码:

    #include <stdio.h>
    #define N 51
    
    bool dp[N][N][N][N] = {0};
    bool vis[N][N][N][N] = {0};
    
    int F(int a, int b, int c, int d)							// 一个相似记忆化搜索的过程
    {
    	if(!vis[a][b][c][d]){									// 假设后继状态为P状态,则此状态为N状态
    		if(a >= 1 && !F(a - 1, b, c, d)) dp[a][b][c][d] = 1;			// 从 a 中某堆拿走一个。消失
    		if(b >= 1 && !F(a + 1, b - 1, c, d)) dp[a][b][c][d] = 1;		// 从 b 中某堆拿走一个。变成 a
    		if(c >= 1 && !F(a, b + 1, c - 1, d)) dp[a][b][c][d] = 1;		// 从 c 中某堆拿走一个。变成 b
    		if(d >= 1 && !F(a, b, c + 1, d - 1)) dp[a][b][c][d] = 1;		// 从 d 中某堆拿走一个,变成 c
    
    		if(a >= 2 && !F(a - 2, b + 1, c, d)) dp[a][b][c][d] = 1;		// 合并 a 中的两堆,变成 b 类的一堆
    		if(b >= 2 && !F(a, b - 2, c, d + 1)) dp[a][b][c][d] = 1;		// 合并 b 中的两堆,变成 d 类的一堆
    		if(c >= 2 && !F(a, b, c - 2, d + 1)) dp[a][b][c][d] = 1;		// 合并 c 中的两堆,变成 d 类的一堆
    		if(d >= 2 && !F(a, b, c, d - 2 + 1)) dp[a][b][c][d] = 1;		// 合并 d 中的两堆,变成 d 类的一堆
    
    		if(a >= 1 && b >= 1 && !F(a - 1, b - 1, c + 1, d)) dp[a][b][c][d] = 1;		// 合并 a、b 中的一堆,变成 c 类的一堆
    		if(a >= 1 && c >= 1 && !F(a - 1, b, c - 1, d + 1)) dp[a][b][c][d] = 1;		// 合并 a、c 中的一堆。变成 d 类的一堆
    		if(a >= 1 && d >= 1 && !F(a - 1, b, c + 1, d - 1)) dp[a][b][c][d] = 1;		// 合并 a、d 中的一堆,变成 c 类的一堆
    		if(b >= 1 && c >= 1 && !F(a, b - 1, c - 1 + 1, d)) dp[a][b][c][d] = 1;		// 合并 b、c 中的一堆,变成 c 类的一堆
    		if(b >= 1 && d >= 1 && !F(a, b - 2, c, d - 1 + 1)) dp[a][b][c][d] = 1;		// 合并 b、d 中的一堆。变成 d 类的一堆
    		if(c >= 1 && d >= 1 && !F(a, b, c - 1 + 1, d - 1)) dp[a][b][c][d] = 1;		// 合并 c、d 中的一堆,变成 c 类的一堆
    	
    		vis[a][b][c][d] = 1;
    	}
    	
    	return dp[a][b][c][d];
    }
    
    int main()
    {
    	int loop, n, t, ct = 1;
    	int a, b, c, d, ans;			// a 表示仅仅有一个石子的堆数,b 表示有仅仅有两个石子的堆数。c 表示有奇数个石子的堆数, d 表示有偶数个石子的堆数
    	scanf("%d", &loop);
    	while(ct <= loop){
    		scanf("%d", &n);
    		a = b = c = d = 0;
    		for(int i = 0; i < n; i ++){
    			scanf("%d", &t);
    			if(t == 1) a ++;
    			else if(t == 2)	b ++;
    			else if(t % 2 == 1) c ++;
    			else d ++;
    		}
    
    		ans = F(a, b, c, d);
    		printf("Case #%d: ", ct ++);
    		if(ans)
    			printf("Alice
    ");
    		else
    			printf("Bob
    ");
    	}
    
    	return 0;
    }


  • 相关阅读:
    遗传算法python实现
    lambda的一些用法
    Python遗传和进化算法框架(一)Geatpy快速入门
    电脑连接小爱同学音箱无法调节音量
    Shell脚本批量修改文件编码为UTF-8
    java实现 批量转换文件编码格式为UTF8
    POM添加规范
    SOFA框架跨包调用报错NoClassDefFoundError
    logger打印日志时加if (logger.isInfoEnabled())/if (logger.isDebugEnabled())
    对象,JSON,字符串,map之间的互转
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/6883936.html
Copyright © 2011-2022 走看看