博弈论初级逗比题:poj2484 && poj2975 && poj2505
博弈论初初级
1:poj2484 A FUNNY GAME
题目大意:
给N个围成一圈的硬币,设编号为1到n,两个杀马特的逗比轮流取,每次可以取走一个硬币,或两个
编号相邻的硬币,问对于给出的N,哪个逗比赢。
解析题目:
乍一看好像特别牛鼻,实际先取的逗比只要不能一下子全部取完,那么稳输= = ,因为这是一张对称
的图,只要后取的能做到取完后是一张中心对称的图,就稳赢,当然前提是先取的取不完。
所以只有N为1 or 2 时先取的赢,其余稳输。
代码:
#include<cstdio> char ch1, ch2; int main ( ) { while (1) { ch1=getchar(), ch2=getchar(); if (ch1=='0') break; if (ch2=='\n'&&ch1<='2')printf("Alice\n"); else printf("Bob\n"); while (ch2!='\n') ch2=getchar(); } }
2:poj2975 Nim游戏
题目大意:
给你N堆石子,告诉你每堆石子中石子的个数,又来了两个杀马特的逗比,他们轮流取,每次可以取任
意一堆石子的任意数量,最后哪个逗比没得取就为输。问先取的是否有必胜的方法?有几种?
题目解析:
将每堆石子的石子数异或在一起,如果大于零,就代表存在必胜的方法:先取一堆石子使得异或和变为
零,即对方面临的是败态,然后根据它的取数保持石子数的异或和为零,最后就赢了。也就是说只有第一步
可选,方案总数即为第一步方案的总数。分别将每堆石子的数量异或回去,看石子数和异或和的大小关系即
可判断可不可取。
代码:
1 #include<cstdio> 2 int n,he,an,a[1004],i; 3 int main ( ) 4 { 5 while (scanf("%d",&n)!=EOF&&n) 6 { 7 he = 0, an = 0; 8 for (i=1; i<=n; i++) scanf("%d",&a[i]),he^=a[i]; 9 if (!he) { printf("0\n"); continue; } 10 for (i=1; i<=n; i++) if ((he^a[i]) <= a[i]) an++; 11 printf("%d\n",an); 12 } 13 }
3:poj2505 一个垒乘的游戏
题目大意:
给出一个N,两个杀马特的逗比从同一个1开始,每次可以把这个数乘2~9中的任意数,最后先乘到>=n
的胜。
题目解析:
倒推:比如轮到一个逗比时这个数已经>=N了,那么这个逗比就输了,也就是说面临[n,+无穷大)的必
定败,那么如果倒退一步操作,也就是说对于这个数,你能通过乘鱼2~9中的一个数使它达到上述区间,那
么这个数就是一个必胜数,比如n-1,随便乘都能达到上述区间,这个区间的上限是n-1,但下限呢 ?就是
[(n-1)/ 9 ]+1;
倒退的过程就是:
由开始的比败区间[n,+无穷大) 推出 上一个必胜区间, 再通过当前必胜区间推出上一个必
败区间,最后看1 属于哪个区间即可判断先手必败还是必胜。
代码:
1 #include<cstdio> 2 long long n,f,i,l; 3 int main ( ) 4 { 5 while (scanf("%I64d",&n)!=EOF) 6 { 7 f = 0,i = 1, l= 9; 8 while (i<n) i*=l, l=18/l, f=1-f; 9 if (f) printf("Stan wins.\n"); 10 else printf("Ollie wins.\n"); 11 } 12 }
END。