2 1000 1 1 100
Lose Win
#include<iostream> using namespace std; int main() { int k; long m,n; cin>>k; while(k--) { cin>>n>>m; if(n%(m+1)==0) cout<<"Lose"<<endl; else cout<<"Win"<<endl; } }
小王喜欢与同事玩一些小游戏,今天他们选择了玩取石子。
游戏规则如下:共有N堆石子,已知每堆中石子的数量,并且规定好每堆石子最多可以取的石子数(最少取1颗)。
两个人轮流取子,每次只能选择N堆石子中的一堆,取一定数量的石子(最少取一个),并且取的石子数量不能多于该堆石子规定好的最多取子数,等哪个人无法取子时就表示此人输掉了游戏。
假设每次都是小王先取石子,并且游戏双方都绝对聪明,现在给你石子的堆数、每堆石子的数量和每堆石子规定的单次取子上限,请判断出小王能否获胜。
2 1 1000 1 2 1 1 1 1
Lose Lose
算法:
巴什博弈和尼姆博弈的杂糅
因为尼姆博弈要求对每一堆石子可以取1-全部,而这道题限制了个数,就成为了巴什博弈。那为什么可以用尼姆博弈的思想来求解呢?
因为我们可以发现,当我们使用巴什博弈取到最后一次时,得到的n%(m+1)结果肯定<m,这样就符合了尼姆博弈的要求,进而可以用尼姆博弈的异或运算来求解。
代码:
#include<cstdio> int main(){ int T; scanf("%d",&T); while(T--){ int m,n,g,sum=0; scanf("%d",&g); while(g--){scanf("%d%d",&m,&n);sum ^= m % (n + 1);} puts(sum?"Win":"Lose"); } }
规则: 有x个石子,两人轮流取,最多取y个,最少取z个,且z<=y,没得取的人输,两个人都按照最优策略进行游戏
有y个石子,两人轮流取,可以取x个,x属于数集X,没得取的人输,两个人都按照最优策略进行游戏,问哪些是必胜态。
#include <iostream> #include <vector> using namespace std; #define MAX_N 10000 bool win[MAX_N]; int main(){ int n,x; cin>>x>>n; vector<int> s(n,0); int z,y; cin>>z>>y; //for(int i=0;i<n;i++){ // cin>>s[i]; //} win[0]=false; for(int j=1;j<=x;j++){ win[j]=false; for(int i=z;i<=y;i++){ win[j] |= i<=j && !win[j-i]; } } if(win[x])cout<<"first"<<endl; else cout<<"second"<<endl; return 0;}
小王喜欢与同事玩一些小游戏,今天他们选择了玩取石子。
游戏规则如下:共有N堆石子,已知每堆中石子的数量,两个人轮流取子,每次只能选择N堆石子中的一堆,取一定数量的石子(最少取一个),取过子之后,还可以将该堆石子中剩下的任意多个石子中随意选取几个放到其它的任意一堆或几堆上。等哪个人无法取子时就表示此人输掉了游戏。注意,一堆石子没有子之后,就不能再往此处放石子了。
假设每次都是小王先取石子,并且游戏双方都绝对聪明,现在给你石子的堆数、每堆石子的数量,请判断出小王能否获胜。
例如:如果最开始有4堆石子,石子个数分别为3 1 4 2,而小王想决定要先拿走第三堆石子中的两个石子(石子堆状态变为3 1 2 2),然后他可以使石子堆达到的状态有以下几种:
3 1 2 2(不再移动石子)
4 1 1 2(移动到第一堆一个)
3 2 1 2(移动到第二堆一个)
3 1 1 3(移动到第四堆一个)
5 1 0 2(全部移动到第一堆)
3 3 0 2(全部移动到第二堆)
3 1 0 4(全部移动到最后)
3 2 1 3 2 1 1 0
Win Lose
算法:
如果石子能够两两配对,每一对中的两堆石子的个数相同,那么就是必败态,先拿的输,先拿的将必败态转化为必胜态,后拿的可以使自己拿完后仍然能够使得两两配对,且每一对的数目相同。这样就又将必败态留给对手。最后可能会变成(1, 1)的情况,这样先拿的输,后拿的赢。所以如果n是奇数的话,就不能能出现两两配对的状态那么肯定是必胜态。
结论是:如果N是奇数先手胜,如果是偶数,那么判断石子数量出现的次数是否为偶数,都是偶数那就是后者胜,只要有一个不是偶数那么先者胜。
例如4 2 1 3 2这组数据,n是偶数,1出现一次,2出现两次,3出现一次,不是所有的数出现的次数都是偶数,所以先者胜。
4 2 1 1 2,n是偶数,1和2都出现两次,所以先者败。
代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int a[103]; int main() { int n; while(scanf("%d",&n),n) { int b; memset(a,0,sizeof(a)); for(int i=0;i<n;i++) { scanf("%d",&b); a[b]++; } int f=0; if(n%2!=0) {printf("Win\n");continue;} for(int i=0;i<=100;i++) { if(a[i]%2!=0) { f=1; break; } } if(f) printf("Win\n"); else printf("Lose\n"); } return 0; }
2 1 8 4 4 7
0 1 0
算法:
威佐夫博奕,已知k=b-a,可求出ak,如果ak==a,则必败。
代码:
#include<iostream> #include<cstdio> #include<cmath> using namespace std; int main() { int a,b; double w=(1.0+sqrt(5.0))/2.0; while(scanf("%d %d",&a,&b)!=EOF) { if(a>b) swap(a,b); if(a==(int)floor((b-a)*w)) printf("0\n"); else printf("1\n"); } }
2.从第二次开始,每个人取的石子数至少为1,至多为对手刚取的石子数的两倍。
himdd事先想知道自己会不会赢,你能帮帮他吗?(每次himdd先手)
2 5 6
No No Yes
算法:
斐波那契博弈问题:
当n为Fibonacci数的时候,必败。
代码:
#include<stdio.h> #include<stdlib.h> long long a[100]; int main() { int i,j,ok; long long m; a[1]=a[2]=1; for(i=3;i<=100;i++) a[i]=a[i-1]+a[i-2]; while(scanf("%lld",&m)!=EOF) { ok=1; for(i=2;i<=92&&m<=a[92];i++) if(a[i]==m) { ok=0; printf("No\n"); break; } if(ok) printf("Yes\n"); } return 0; }
3 2 1 1 3 3 8 11 2 5 10
HRDV HRDV PIAOYI
#include<iostream> #include<stdio.h> using namespace std; void in(int &a) { char ch; while((ch=getchar())<‘0‘||ch>‘9‘); for(a=0;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) a=a*10+ch-‘0‘; } int main() { int T;in(T); while(T--) { int n;in(n); int ans=0; for(int i=0;i!=n;++i) { int b;in(b); ans^=b; } if(ans) puts("PIAOYI"); else puts("HRDV"); }return 0; }
Yougth和Hrdv玩一个游戏,拿出n个石子摆成一圈,Yougth和Hrdv分别从其中取石子,谁先取完者胜,每次可以从中取一个或者相邻两个,Hrdv先取,输出胜利着的名字。
2 3
Hrdv Yougth
#include<cstdio> int n; int main() { while(~scanf("%d",&n)) printf(n>=3?"Yougth\n":"Hrdv\n"); return 0; }
有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。如果你胜,你第1次怎样取子?
1 2 5 72 20 0
013 53 54 710 01 2
#include<iostream> #include<cstdio> #include<cmath> using namespace std; bool judge(int a,int b){ if(a>b) swap(a,b); double w=(1.0+sqrt(5.0))/2.0; if(a==(int)floor((b-a)*w)) return true; return false; } void fun(int a,int b){ for(int i=1;i<=b;i++){ if(judge(a-i,b-i)){ cout<<a-i<<" "<<b-i<<endl; break; } } for(int i=1;i<=b;i++){ if(judge(a,b-i)){ if(a<b-i) cout<<a<<" "<<b-i<<endl; else cout<<b-i<<" "<<a<<endl; break; } } if(a!=b){ for(int i=1;i<=a;i++){ if(judge(a-i,b)){ if(a-i<b) cout<<a-i<<" "<<b<<endl; else cout<<b<<" "<<a-i<<endl; break; } } } } int main() { int a,b; double w=(1.0+sqrt(5.0))/2.0; while(scanf("%d %d",&a,&b)!=EOF , a && b) { if(a>b) swap(a,b); if(a==(int)floor((b-a)*w)) printf("0\n"); else {printf("1\n"); fun(a,b); } } }
最近TopCoder的Yougth和Hrdv在玩一个游戏,游戏是这样的。
有n堆石子,两个人轮流从其中某一堆中任意取走一定的石子,最后不能取的为赢家,注意: 每次只能从一堆取任意个,可以取完这堆,但不能不取。
假设Yougth先取,输入赢了的人名字、
3 2 1 1 3 3 8 11 2 5 10
Yougth Hrdv Yougth
#include<stdio.h> int main() { int T,n,a,i,result,count; scanf("%d",&T); while(T--) { scanf("%d",&n); result=0; count=0; for(i=1;i<=n;i++) { scanf("%d",&a); result=result^a; if(a>1) count++; } if((count&&result)||(!count&&!result)) printf("Yougth\n"); else printf("Hrdv\n"); } return 0; }
不知不觉取石子已经到第十道了。地球上的石子也快要取完了!
开个玩笑,当然还是有很多石子的,取石子的题目也是做不完的,今天又来了一道!
有n堆石子,每一堆的规则如下:
第一堆每次只能取2的幂次(即:1,2,4,8,16…);
第二堆只能取菲波那契数列中的元素(即每次只能取1,2,3,5,8…等数量,斐波那契数即后面的数是前面两个数的和);
第三堆可以取任意多个,最小1个,最多可以把这一堆石子取完;
第四堆只能取1和偶数个(即:1,2,4,6,8,10...);
第五堆只能取奇数个(即:1,3,5,7,9.....);
好吧,这样下去太烦人了,六堆及其以后每堆最多取的数量为堆数编号,即第六堆只能取(1,2,3,4,5,6),第七堆只能取(1,2,3,4,5,6,7)....
别看规则很多,但Yougth和Hrdv都是聪明人,现在由Yougth先取,比赛规定谁先取完所有石子既为胜者,输出胜者的名字。
6 2 4 2 3 6 7
Hrdv
最近ZKC同学在学博弈,学到了一个伟大的博弈问题--威佐夫博弈。
相信大家都学过了吧?没学过?没问题。我将要为你讲述一下这个伟大的博弈问题。
有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。
游戏规定,每次有两种不同的取法:
一是可以在任意的一堆中取走任意多的石子;
二是可以在两堆中同时取走相同数量的石子。
最后把石子全部取完者为胜者。
我们今天要做的是求前n个必败态。
什么是必败态?比如我们把(a,b)称为一种状态,a,b分别为两堆石子中所剩的数目。如果a=0,b=0,我们说该种状态为必败态,因为我不能再进行游戏,即使是可以进行,那也是必败的,你知道,游戏的我们都是非常聪明的。(0,0)(1,2)(3,5)...都是必败态,我们今天要做的就是求前n个必败态。不会?好吧!
我再告诉你:假设第n个必败态为(a,b)a为前n-1个必败态中没有出现的最小自然数,b=a+n。这下大家应该明白了吧。好吧,我们的任务就的要前n个必败态。规定第0个必败态为(0,0)。
3 1
(0,0)(1,2)(3,5)(4,7) (0,0)(1,2)
#include <iostream> #include <string.h> using namespace std; #define maxn 100010 int a[maxn]; int b[maxn*3]; int main(){ memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); a[0]=a[1]=0; b[0]=1; int mi=1; for(int i=1;i<maxn;i++){ a[i]=mi; b[mi]=1; b[mi+i]=1; for(int j=mi;j<maxn;j++){ if(b[j] == 0){ mi=j; break;} } } int n; while(cin>>n){ for(int i=0;i<=n;i++){ cout<<"("<<a[i]<<","<<a[i]+i<<")"; } cout<<endl; } return 0;}
原文地址:http://blog.csdn.net/wximo/article/details/25697589