hdu1527-威佐夫博弈(Wythoff Game)
2013-08-08 19:50
253 查看
hdu1527-威佐夫博弈
Problem Description
有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。
首先,我们想到打表查看,小规模博弈情况:
程序如下:
方法一:
![](https://img-blog.csdn.net/20130928161206890?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3VucXVhbmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
递归版:
运行结果如下:
![](https://img-blog.csdn.net/20130808202828406?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3VucXVhbmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
由上图可知:
前几个必败点如下:(0,0),(1,2),(3,5),(4,7),(6,10),(8,13)……可以发现,对于第k个必败点(m(k),n(k))来说,m(k)是前面没有出现过的最小自然数,n(k)=m(k)+k。
判断一个点是不是必败点的公式与黄金分割有关。严格的推导,请读者自己证明。
m(k) = k * (1 + sqrt(5))/2
Problem Description
有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。
首先,我们想到打表查看,小规模博弈情况:
程序如下:
方法一:
#include <iostream> #include <cstdio> using namespace std; int d[100][100]; void welfol(int n) { d[0][0]=0; for(int i=1; i<=n; i++) { d[i][i]=1; d[0][i]=d[i][0]=1; } for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) { if(i==j)continue; int f=1; for(int k=1; f&&k<i; k++) if(d[i-k][j]==0) { d[i][j]=1; f=0; } for(int k=1; f&&k<j; k++) if(d[i][j-k]==0) { d[i][j]=1; f=0; } for(int k=1; f&&k<min(i,j); k++) if(d[i-k][j-k]==0) { d[i][j]=1; f=0; } } } void show(int n) { printf(" "); for(int i=0; i<=n; i++) printf("%3d",i); printf("\n"); for(int i=0; i<=n; i++) { printf("%3d",i); for(int j=0; j<=n; j++) printf("%3d",d[i][j]); printf("\n"); } } int main() { welfol(20); show(20); return 0; }
递归版:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int ans[100][100]; int solve(int m,int n) { if(m==0&&n==0) return 0; if(m==0||n==0) return 1; if(m==n) return 1; if(ans[m] !=-1) return ans[m] ; for(int i=1;i<=m;i++) { ans[m-i] =solve(m-i,n); if(ans[m-i] ==0) return 1; } for(int i=1;i<=n;i++) { ans[m][n-i]=solve(m,n-i); if(ans[m][n-i]==0) return 1; } for(int i=1;i<=min(m,n);i++) if(solve(m-i,n-i)==0) return 1; return 0; } int main() { memset(ans,-1,sizeof(ans)); ans[0][0]=0; solve(23,22); printf(" "); for(int i=0;i<20;i++) printf("%2d ",i); printf("\n"); for(int i=0; i<20; i++) { printf("%2d ",i); for(int j=0; j<20; j++) printf("%d ",ans[i][j]); printf("\n"); } return 0; }
运行结果如下:
由上图可知:
前几个必败点如下:(0,0),(1,2),(3,5),(4,7),(6,10),(8,13)……可以发现,对于第k个必败点(m(k),n(k))来说,m(k)是前面没有出现过的最小自然数,n(k)=m(k)+k。
判断一个点是不是必败点的公式与黄金分割有关。严格的推导,请读者自己证明。
m(k) = k * (1 + sqrt(5))/2
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; #define GOLDEN 1.6180339887498 int main() { int n,m,k; while(cin>>n>>m) { if(n<m)swap(n,m); k=n-m; k=(int)(k*(1.0+sqrt(5.0))/2); if(k==m) printf("0\n"); else printf("1\n"); } return 0; }
相关文章推荐
- 1067 取石子游戏 威佐夫博弈(Wythoff Game)
- hdu-2177(威佐夫博弈。Wythoff Game)
- 威佐夫博弈(Wythoff Game)
- POJ 1067 威佐夫博弈(Wythoff Game)问题 (取石子游戏)
- 威佐夫博弈(Wythoff Game)
- 威佐夫博弈(Wythoff Game)
- 威佐夫博弈(Wythoff Game)初识 HDU 1527 POJ 1067
- poj 1067 取石子游戏——威佐夫博弈(Wythoff Game)
- poj1067 hdu1527 取石子游戏 威佐夫博弈
- hdu1527,poj1067 取石子游戏 威佐夫博奕(Wythoff Game)
- [博弈] poj 1067 #裸的Wythoff Game
- [博弈 Wythoff Game]poj 1067
- POJ 1067: Wythoff Game【博弈】
- 威佐夫博弈->HDU1527
- NYOJ-837-Wythoff Game 【威佐夫博奕】
- HDU1527:取石子游戏(威佐夫博弈)
- HDU1527威佐夫博弈入门题 直接代公式
- HDOJ 2177 取(2堆)石子游戏 博弈 威佐夫博奕变形(Wythoff Game)
- Game of Taking Stones (大数 + 威佐夫博弈 java写的)
- Game of Taking Stones (hdu5973)——2016大连现场赛C题 威佐夫博弈