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


  • 相关阅读:
    实时27实战机器学习:图片验证码识别(Java实现)
    大屏26深度学习模型来从文档图片中自动化地提取出关键信息成为一项亟待解决的挑战
    f-string想必作为Python3.6版本开始引入的特性,通过它我们可以更加方便地向字符串中嵌入自定义内容
    大屏25JAVA+selenium+tess4j识别登陆验证码截图与识别
    前端12 highcharts和echarts选择
    大屏20基于 Selenium 的 Web 自动化测试框架完美版自动化解决方案 [开源项目]
    大屏24字典python+selenium的行为
    大屏23Tesseract字库训练Tesseract 3
    大屏21解决数据问题python-tesseract-ocr的安装及使用
    大屏22解决数据问题java浏览器源.docx
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/6883936.html
Copyright © 2011-2022 走看看