MCS 简单博弈
来源:互联网 发布:阿里巴巴商机助理 mac 编辑:程序博客网 时间:2024/06/10 07:11
今天题解重点写思路!!
博弈参考博客:
http://blog.csdn.net/shahdza/article/details/7796775
Problem A:
原题链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1079 (HDU 1079 )
思路:
目标是 11.4。可以推出11.3和11.1一定会胜利
在向前推可以得出10.30 10.28 10.26 10.24…..(我把10月份的都写出来了)都是必胜的。
那么大致可以得出月份+日期为偶数为必胜状态。
如果是7月24呢( Adam输 )?首先他要经过
步骤:7月24→8月24→9月24→10月24。
玩家:Adam→Eve→Adam→Eve
此时为Eve必胜。
但是:9 月30和11月30是两个例外(自己可以推一推)
题目中有说道闰年(没卵用)。2月29。可以转换成3月1,或者3月29。但是因为Adam先手。他可以选择一种。
但是3月1和3月29的必胜性和是否闰年没关系。此时都是EVE必胜
所以可以得出结论:
只需判断月份+日期的奇偶性和两个特例就可以了
代码如下:
#include <iostream>#include <cstdio>#include <cstring>using namespace std;int main(){ int T; scanf("%d",&T); while( T-- ) { int y,m,d; scanf("%d %d %d",&y,&m,&d); if( ( m + d ) % 2 == 0 || d == 30 && m == 9 || d == 30 && m == 11 ) printf("YES\n"); else printf("NO\n"); } return 0;}
Problem B :
原题链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1525( HDU 1525 )
思路:
这题是标准的威佐夫博弈问题。
但是我用的并不是模板方法。一下为kuangbin大神的代码。我只是看懂了
先交换A和B的值。保证A>=B
1.如果A可以整除B。那么Stan可以直接把Ollie弄死
理由: 只要将A中拿走A-(B+1)个。就可以使得剩下B+1和B个。这样无论后手怎么拿都是胜利的。如果Ollie不按套路出牌强行剩下B-1和B个。那么Stan可以剩下B-1和B-2个。只需保证一堆比另一堆多1个就可以了。到了最后剩1和2的时候。无论Ollie有什么套路。他都输了
2.同理 a/b >= 2也是一个意思。可以判断怎么拿可以进入奇异状态。
3.最麻烦的就是不是以上两种情况。那么每次都取余(这样已经不会有什么特殊情况了。只有等到其中一个变成0)。注意:这种情况每次要更改胜利的人。不然会WA
代码如下:
#include <iostream>#include <cstdio>#include <cstring>using namespace std;int main(){ int a,b; while( ~scanf("%d %d",&a,&b) ) { if( a == 0 && b == 0 ) break; int win = 0; if( a < b ) swap(a,b); while( b ) { if( a % b == 0 || a / b >= 2 ) break; a = a - b; swap( a,b); win ^= 1 ; } if( win == 0 ) printf("Stan wins\n"); else printf("Ollie wins\n"); } return 0;}
Problem C:
原题链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1564 ( HDU 1564 )
思路:
首先分两种情况:
1.走完n*n个的格子。那么需要注意此时要走n*n-1步。说明了n为奇数是走偶数步。n为偶数时走奇数步。所以n为偶数时,先走的胜利(因为最后一步是他走的)
2.不按套路出牌。围追堵截(在没有走完全部格子的情况下就结束了)
此时可以得到一样的结论。
因为不会插入图片。示例不好说明。可以自己去试一试。
代码如下:
#include <iostream>#include <cstdio>#include <cstring>using namespace std;int main(){ int N; while( ~scanf("%d",&N) ) { if( N == 0 ) break; if( N % 2 == 0 ) printf("8600\n"); else printf("ailyanlu\n"); } return 0;}
Problem D:
原题链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1864 (HDU 1864)
思路:
标准的巴什博奕。
每次都给对手留下m+1或者他的整数倍。这样如果他去了K个。你都可以取完或者取m+1-K个。这样无论他怎么取。你最后都可以直接收。所以在开始的时候直接判断n和m+1之间的关系就可以了。如果n刚好为m+1的整数倍。那么你就输了。
注意:
这里所说的1不是一个定值。这个值只表示在该游戏中所取得最小值。底下有另外一道题可以说明
代码如下:
#include <iostream>#include <cstdio>#include <cstring>#include <cmath>using namespace std;int main(){ int N; scanf("%d",&N); while( N-- ) { int n,m; scanf("%d %d",&n,&m); if( n % ( m + 1 ) != 0 ) printf("first\n"); else printf("second\n"); } return 0;}
Problem E:
原题链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2147 (HDU 2147)
思路:
从右上角到左下角。总步数为奇数时。先走的人可以获胜。
最短路(只算直走) = n + m -2(起点和转角点)
1.两条边都是偶数。
可以。因为这样可以倒数第二行或者第二列的时候向斜下方走。这样可以把两步改成一步。使偶数步变成奇数步可以达成目的。因为是在倒数行变道。对手已经没有机会变道(原本直线前行。突然向斜下方走一步)了。所以kiki可以赢
2.一条为奇数。一条为偶数
可以。本身就可以直接达成目的。
3.两条边都是奇数。
不行。此时n + m - 2 比为偶数。而且在倒数第二行或第二列的时候是ZZ走。就算你在前面一步强行变道。你认为根据最优方案她不会变回来吗?
注意:
斜着走要的步数其实就是n和m中较小的那个值
代码如下:
#include <iostream>#include <cstdio>#include <cstring>#include <cmath>using namespace std;int main(){ int n,m; while( ~scanf("%d %d",&n,&m) ) { if( n == 0 && m == 0 ) break; if( ( n % 2 == 1 && m % 2 == 0 ) || ( n % 2 == 0 && m % 2 == 1) || ( n % 2 == 0 && m %2 ==0 ) ) printf("Wonderful!\n"); else printf("What a pity!\n"); } return 0;}
Problem F:
原题链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2897 ( HDU 2897 )
思路:
这题也是巴什博奕。
与前面那题不同之处在于。这题每次最少要取P个最多Q个。剩下P个要一次全收
所以 之前的n对(m +1 )取余改成 n对(p + q )取余就可以了。但是要注意。取余所剩下的值一定要不大于p。如果大于p。根据这题的规则你就输了。
代码如下:
#include <iostream>#include <cstdio>#include <cstring>#include <cmath>using namespace std;int main(){ int n,p,q; while( ~scanf("%d %d %d",&n,&p,&q) ) { if( n % ( p + q ) != 0 && n % ( p + q ) <= p ) printf("LOST\n"); else printf("WIN\n"); } return 0;}
Problem G:
原题链接:
http://poj.org/problem?id=1067 (POJ 1067)
思路:
这道题用威佐夫博奕
首先:保证a是较小的值
然后威佐夫博奕的公式:
aK = 是前面未出现的最小数。
bk = aK + K;
所以这里用b - a 就可以求得K。
接着利用公式就可以得出答案。
(那个公式是怎么来的。可以百度百科威佐夫博奕。里面有证明)
依据公式:
把计算得到的值向下取整和a值做比较就可以判断当前是不是奇异态
在这题中。一开始为奇异态就输了。
代码如下:
#include <iostream>#include <cstdio>#include <cstring>#include <cmath>using namespace std;int main(){ int a,b; while(~scanf("%d %d",&a,&b)) { if ( a > b ) swap( a, b ); int k = b - a; double j = ( 1 + sqrt( (double)5 ) ) / (double)2; if( a == floor( k* j ) ) printf("0\n"); else printf("1\n"); } return 0;}
Problem H:
本体我也不会做。第三种算法看不懂。请看大神题解。链接如下:
http://m.blog.csdn.net/blog/u013634213/38835695
- MCS 简单博弈
- 简单博弈
- 简单博弈
- 简单博弈
- 简单博弈
- 简单的拍卖博弈
- POJ 2484 简单博弈
- cf div_124_a(简单博弈)
- 简单博弈10道
- 简单博弈整理
- 简单博弈题
- 简单博弈小结
- 简单博弈总结
- hdu 2897简单博弈
- hdu1907John 简单博弈
- poj2484----简单博弈
- 简单巴什博弈
- SG博弈简单题
- php 读取某目录下的所有文件
- 《项目管理修炼之道》阅读笔记(1)
- ant实现批量打包android应用
- python dir __dict__
- [leetcode] 241.Different Ways to Add Parentheses
- MCS 简单博弈
- 九度oj 1075
- linux(四)
- git 常用命令
- oracle 查看用户所在的表空间
- ZOJ Team Formation 3870【位运算】
- uva725_一道水题(优化到了29ms)
- POJ 2631 -- Roads in the North【树的直径 && 裸题】
- 关于百度地图开发中可能遇到Conversion to Dalvik format failed with error 1