博弈论习题
来源:互联网 发布:无极郭敬明知乎 编辑:程序博客网 时间:2024/05/19 04:27
poj2234
真。裸题。
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int main(){ int n; while(~scanf("%d",&n)) { int ans=0,s; for(int i=0;i<n;i++) { scanf("%d",&s); ans^=s; } if(ans==0) printf("No\n"); else printf("Yes\n"); }}
Hdu2176
一看知道是尼姆博弈,暴力做,TLE了,在这里记一下,有个好神奇的东西,一个数n和m异或之后再和m异或会重新变成n。还是太菜了,看了尼姆博弈,但是过程也看的不是特别细,第一次取石子还是没理解透彻。
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int a[200005];int main(){ int n; while(~scanf("%d",&n)&&n) { int t=0; for(int i=0;i<n;i++) { scanf("%d",&a[i]); t=t^a[i]; } if(t==0) printf("No\n"); else { int temp; printf("Yes\n"); for(int i=0;i<n;i++) { temp=t^a[i]; if((temp^t^a[i])==0) { if((t^a[i])<a[i]) printf("%d %d\n",a[i],t^a[i]); } } } }}
poj2975
和上面的题差不多,也是求第一步能有几种走法,把上面那个改一改就差不多了。
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int a[1005];int main(){ int t; while(~scanf("%d",&t)&&t) { int ans=0; for(int i=0; i<t; i++) { scanf("%d",&a[i]); ans^=a[i]; } int sum=0; if(ans==0) { printf("0\n"); continue; } else { int temp; for(int i=0; i<t; i++) { temp=ans^a[i]; if((temp^ans^a[i])==0&&(ans^a[i])<a[i]) { sum++; } } } printf("%d\n",sum); }}
Hdu1730
没什么好说的,裸地尼姆博弈
#include<cstdio>#include<algorithm>#include<cstring>using namespace std;int a[1005];int main(){ int n,m; while(~scanf("%d %d",&n,&m)) { int aa,b,t=0; for(int i=0;i<n;i++) { scanf("%d %d",&aa,&b); a[i]=max(aa,b)-min(aa,b)-1; t=t^a[i]; } if(t==0) printf("BAD LUCK!\n"); else printf("I WIN!\n"); }}
poj2960
比较经典的SG函数的题吧,一直WA。。。原因是求SG值的地方错了(虽然我也不知道哪里错了)蓝瘦。。。。。
题意比较明显,就是告诉你一个集合S,只能拿这个集合里有的数,有n个例子,每个例子有m堆,把这m堆分解成m个子游戏,分别求SG值,然后再异或,得到答案是0就输出L不然就输出W(注意他是n个例子每个例子下面就是输出不要攒到一起输出,我就被样例给骗了。)还是自己太弱了吧。继续加油。
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int s[105],d,dp[10005],t[105];bool vis[10005];const int temp =10005;int main(){ int n,m,k; while(~scanf("%d",&n)&&n) { memset(dp,0,sizeof dp); memset(vis,0,sizeof vis); memset(s,0,sizeof s); memset(t,0,sizeof t); for(int i=0; i<n; i++) scanf("%d",&s[i]); sort(s,s+n); dp[0]=0; for(int i=1; i<temp; i++) { memset(vis,0,sizeof vis); for(int j=0; j<n; j++) { if(i-s[j]>=0) vis[dp[i-s[j]]]=1; else break; } for(int j=0;; j++) { if(!vis[j]) { dp[i]=j; break; } } } scanf("%d",&m); int mount=0; for(int i=0; i<m; i++) { scanf("%d",&k); int ans=0; for(int j=0; j<k; j++) { scanf("%d",&d); ans=ans^(dp[d]); } if(ans==0) { printf("L"); } else printf("W"); } printf("\n"); }}
网上都是非常简短的函数,我写的有些丑。
poj1067
威佐夫博弈的裸题。给你x,y,如果x>y,交换。z=y-x。
然后w=(int)(((sqrt(5.0)+1)/2)*z)
然后判断w和x相不相等。相等就是先手必败,否则就是必胜。
#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>using namespace std;int main(){ int n,m; while(~scanf("%d %d",&n,&m)) { int x=min(n,m); int y=max(n,m); int z=y-x; int w=(int)(((sqrt(5.0)+1)/2)*z); if(w==x) printf("0\n"); else printf("1\n"); }}
poj2425
开始读题一直没读懂。搞样例搞了好久。。。。
大概就是给你一个图,然后告诉你上面那几个点上有棋子,然后双方轮流走谁先无棋可走谁就输了。和SG函数的定义很像。因为一些细节一直做不出来。。。。建图建的不好,想省事顺便练练存图,用vector结果初始化-1卡住了,又改回二维数组。费了老大功夫。。以后看数据量不大还是用二维数组吧。。。。
#include<cstdio>#include<cstring>#include<algorithm>#include<vector>using namespace std;int adj[1050][1050];int sg[1005];int n;int serch(int n1){ bool vis[1005]; if(sg[n1]!=-1) return sg[n1]; memset(vis,0,sizeof vis); for(int i=0; i<n; i++) { if(adj[n1][i]!=-1) { vis[serch(i)]=1; } } int w=0; while(vis[w])w++; return sg[n1]=w;}int main(){ while(~scanf("%d",&n)) { memset(sg,-1,sizeof sg); memset(adj,-1,sizeof adj); for(int i=0; i<n; i++) { int m,t; scanf("%d",&m); if(m==0) { sg[i]=0; } for(int j=0; j<m; j++) { scanf("%d",&t); adj[i][t]=1; } } int m; while(~scanf("%d",&m)&&m) { int x; int ans=0; for(int i=0; i<m; i++) { scanf("%d",&x); ans^=serch(x); } if(ans==0) printf("LOSE\n"); else printf("WIN\n"); } }}
poj1704
做过一次的,还错了。。。
题意是一行棋盘上有一堆棋子,然后轮流向左移。谁先无法移动谁输。
将两个棋子之间的格子数目看做一堆棋子,如果总棋子数是奇数,就把第一个和边界之间的格子数目看成一堆棋子(注意,奇数)然后nim博弈。
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int main(){ int p[1000]; int t,n; scanf("%d",&t); while(t--) { memset(p,0,sizeof p); scanf("%d",&n); int mount=0; if(n%2==1) p[mount++]=0; for(int i=0; i<n; i++) { int a; scanf("%d",&a); p[mount++]=a; } sort(p,p+mount); int x=0; for(int i=0; i+1<mount; i+=2) { x^=(p[i+1]-p[i]-1); } if(x==0) printf("Bob will win\n"); else puts("Georgia will win"); }}
poj1740
没做出来,看的题解。。。
大概就是偶数的时候如果排序之后的12、34…..都相等的话,无论先手怎么走后手模仿先手必败。其他就是先手必胜
而奇数先手只要把最大的拿走然后创造一个12 34 ….都相等的局面就好了。先手必胜。
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int a[1005];int main(){ int n; while(~scanf("%d",&n)&&n) { memset(a,0,sizeof a); for(int i=0; i<n; i++) scanf("%d",&a[i]); int flag=0; if(n%2==1) { printf("1\n"); continue; } else { sort(a,a+n); for(int i=0;i<n;i+=2) { if(a[i]!=a[i+1]) { flag=1; } } } printf("%d\n",flag); }}
poj2068
看着网上的一堆题解发憷,都是当水题来做,蓝瘦。
dp[i][j]表示第i个人时候还有j个石子,然后当j=0时为1;
后继里面有存在0的这个状态就是1;
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int a[30],dp[30][8200];int n,s;int slove(int x,int S){ if(dp[x][S]!=-1)return dp[x][S]; for(int i=1; i<=a[x]; i++) { int t=S-i; if(t<0) break; int y; if(x+1>=2*n)y=0; else y=x+1; if(slove(y,t)==0)return dp[x][S]=1; } return dp[x][S]=0;}int main(){ while(~scanf("%d",&n)&&n) { memset(a,0,sizeof a); scanf("%d",&s); for(int i=0; i<2*n; i++) scanf("%d",&a[i]); memset(dp,-1,sizeof dp); for(int i=0; i<2*n; i++) dp[i][0]=1; int ans=slove(0,s); if(ans==0) printf("0\n"); else printf("1\n"); }}
- 博弈论习题
- 博弈论习题分析
- 博弈论
- 博弈论
- 博弈论
- 博弈论
- 博弈论
- 博弈论
- 博弈论
- 【博弈论】
- 博弈论
- 博弈论
- 博弈论
- 博弈论
- 博弈论
- 博弈论
- 博弈论
- 博弈论
- hdu 1072 Nightmare
- 鸡啄米:模态、非模态对话框
- 使用Google cloud platform SDK 调用 google translate API
- Genymotion无法启动
- PuTTY+Xming实现X11的ssh转发
- 博弈论习题
- 树之基础
- LeetCode 46 Permutations + LeetCode 47 Permutations II
- [ACM] POJ 3087 Shuffle'm Up
- HDUOJ 2018 母牛的故事
- Hibernate 多对一与一对多的关系
- 加密相关的技术
- JavaScript
- 生成缓存 读取缓存 删除缓存