【算法总结】博弈论相关
〖相关资料〗
〖相关题目〗
1.【bzoj1188】[HNOI2007]分裂游戏
题意:共有n个瓶子,标号为0,1,2.....n-1,第i个瓶子中装有p[i]颗巧克力豆,两个人轮流取豆子,每一轮每人选择3个瓶子,标号为i,j,k,并要保证i<j,j<=k且第i个瓶子中至少要有1颗巧克力豆。随后这个人从第i个瓶子中拿走一颗豆子并在j,k中各放入一粒豆子(j可能等于k)。如果轮到某人而他无法按规则取豆子,那么他将输掉比赛。问先手必胜策略的第一步方案。
分析:hzwerの博客
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cmath> 6 using namespace std; 7 int T,n,a[25],sg[25]; 8 bool mark[20000]; 9 int read() 10 { 11 int x=0,f=1;char c=getchar(); 12 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 13 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 14 return x*f; 15 } 16 void pre() 17 { 18 for(int i=2;i<=21;i++) 19 { 20 memset(mark,0,sizeof(mark)); 21 for(int j=1;j<i;j++) 22 for(int k=1;k<=j;k++) 23 mark[sg[j]^sg[k]]=true; 24 for(int j=0;;j++) 25 if(!mark[j]){sg[i]=j;break;} 26 } 27 } 28 int main() 29 { 30 pre();T=read(); 31 while(T--) 32 { 33 n=read(); 34 for(int i=1;i<=n;i++)a[i]=read(); 35 int ans=0,win=0; 36 for(int i=1;i<=n;i++) 37 if(a[i]&1)ans^=sg[n-i+1]; 38 for(int i=1;i<=n;i++) 39 for(int j=i+1;j<=n;j++) 40 for(int k=j;k<=n;k++) 41 if((ans^sg[n-i+1]^sg[n-j+1]^sg[n-k+1])==0) 42 { 43 win++; 44 if(win==1)printf("%d %d %d\n",i-1,j-1,k-1); 45 } 46 if(!win)printf("-1 -1 -1\n"); 47 printf("%d\n",win); 48 } 49 return 0; 50 }
2.【bzoj1299】[LLH邀请赛]巧克力棒
题意:每次一人可以从盒子里取出若干条巧克力棒,或是将一根取出的巧克力棒吃掉正整数长度。两人轮流,无法操作的人输。 问是否先手必胜。
分析:hzwerの博客
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 int T,n,a[15]; 6 bool yes; 7 int read() 8 { 9 int x=0,f=1;char c=getchar(); 10 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 11 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 12 return x*f; 13 } 14 void dfs(int deep,int sum,int non) 15 { 16 if(deep==n+1) 17 { 18 if(sum==0&&non)yes=true; 19 return; 20 } 21 dfs(deep+1,sum^a[deep],1); 22 dfs(deep+1,sum,non); 23 } 24 int main() 25 { 26 T=10; 27 while(T--) 28 { 29 n=read();yes=false; 30 for(int i=1;i<=n;i++)a[i]=read(); 31 dfs(1,0,0); 32 if(yes)puts("NO"); 33 else puts("YES"); 34 } 35 return 0; 36 }
3.【bzoj1443】[JSOI2009]游戏Game
题意:见原题
分析:ONION_CYCの博客
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 const int N=105; 7 const int M=1e4+5; 8 const int inf=0x3f3f3f3f; 9 const int xx[4]={0,0,-1,1}; 10 const int yy[4]={-1,1,0,0}; 11 int n,m,id,S,T,cnt=1,tot; 12 int map[N][N],col[M],ix[M],iy[M],ans[M]; 13 int first[M],cur[M],q[M],dis[M]; 14 bool vis[M]; 15 char s[N]; 16 struct edge{int to,next,flow;}e[M*20]; 17 void insert(int u,int v,int w) 18 { 19 e[++cnt]=(edge){v,first[u],w};first[u]=cnt; 20 e[++cnt]=(edge){u,first[v],0};first[v]=cnt; 21 } 22 bool bfs() 23 { 24 memset(dis,-1,sizeof(dis)); 25 int head=0,tail=1; 26 q[head]=S;dis[S]=0; 27 while(head!=tail) 28 { 29 int u=q[head++]; 30 for(int i=first[u];i;i=e[i].next) 31 { 32 int v=e[i].to; 33 if(dis[v]!=-1||!e[i].flow)continue; 34 dis[v]=dis[u]+1; 35 q[tail++]=v; 36 } 37 } 38 return dis[T]!=-1; 39 } 40 int dfs(int u,int a) 41 { 42 if(u==T||a==0)return a; 43 int f,flow=0; 44 for(int& i=cur[u];i;i=e[i].next) 45 { 46 int v=e[i].to; 47 if(dis[v]==dis[u]+1&&(f=dfs(v,min(e[i].flow,a)))>0) 48 { 49 e[i].flow-=f;e[i^1].flow+=f; 50 flow+=f;a-=f;if(a==0)break; 51 } 52 } 53 return flow; 54 } 55 void DFS(int x,int f) 56 { 57 vis[x]=true; 58 if(col[x]==f&&x!=S&&x!=T)ans[++tot]=x; 59 for(int i=first[x];i;i=e[i].next) 60 if(e[i].flow==f&&!vis[e[i].to]) 61 DFS(e[i].to,f); 62 } 63 int main() 64 { 65 scanf("%d%d",&n,&m); 66 for(int i=1;i<=n;i++) 67 { 68 scanf("%s",s+1); 69 for(int j=1;j<=m;j++) 70 { 71 if(s[j]=='#')continue; 72 id=(i-1)*m+j;map[i][j]=id; 73 ix[id]=i;iy[id]=j; 74 } 75 } 76 S=0;T=n*m+1; 77 for(int i=1;i<=n;i++) 78 for(int j=1;j<=m;j++) 79 { 80 if(!map[i][j])continue; 81 if((i+j)&1) 82 { 83 insert(map[i][j],T,1); 84 continue; 85 } 86 col[map[i][j]]=1; 87 insert(S,map[i][j],1); 88 for(int k=0;k<4;k++) 89 if(map[i+xx[k]][j+yy[k]]) 90 insert(map[i][j],map[i+xx[k]][j+yy[k]],1); 91 } 92 while(bfs()) 93 { 94 for(int i=S;i<=T;i++)cur[i]=first[i]; 95 dfs(S,inf); 96 } 97 DFS(S,1);memset(vis,0,sizeof(vis));DFS(T,0); 98 if(tot) 99 { 100 printf("WIN\n"); 101 sort(ans+1,ans+tot+1); 102 for(int i=1;i<=tot;i++) 103 printf("%d %d\n",ix[ans[i]],iy[ans[i]]); 104 } 105 else printf("LOSE\n"); 106 return 0; 107 }
4.【bzoj3895】取石子
题意:N堆石子排成一排,轮流操作,每次操作时从下面的规则中任选一个:从某堆石子中取走一个,合并任意两堆石子,不能操作的人输。问是否有先手必胜策略。
分析:iamxymの博客
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=50055; 6 int T,n,x,y,a[55]; 7 bool f[55][N],vis[55][N]; 8 int read() 9 { 10 int x=0,f=1;char c=getchar(); 11 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 12 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 13 return x*f; 14 } 15 bool dfs(int x,int y) 16 { 17 if(vis[x][y])return f[x][y]; 18 vis[x][y]=true; 19 if(y==1)return f[x][y]=dfs(x+1,0); 20 if(x-1>=0&&!dfs(x-1,y))return f[x][y]=true; 21 if(x-2>=0&&!dfs(x-2,y+2+(y>0)))return f[x][y]=true; 22 if(y-1>=0&&!dfs(x,y-1))return f[x][y]=true; 23 if(x-1>=0&&y&&!dfs(x-1,y+1))return f[x][y]=true; 24 return false; 25 } 26 int main() 27 { 28 T=read(); 29 while(T--) 30 { 31 n=read();x=0;y=0; 32 for(int i=1;i<=n;i++) 33 { 34 a[i]=read(); 35 if(a[i]==1)x++; 36 else y+=a[i]+1; 37 } 38 if(y)y--;dfs(x,y); 39 if(f[x][y])puts("YES"); 40 else puts("NO"); 41 } 42 return 0; 43 }
5.【bzoj3105】[cqoi2013]新Nim游戏
题意:见原题
分析:ONION_CYCの博客
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define LL long long 5 using namespace std; 6 int n,p[30],a[105],c[105]; 7 LL ans; 8 int read() 9 { 10 int x=0,f=1;char c=getchar(); 11 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 12 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 13 return x*f; 14 } 15 int main() 16 { 17 n=read(); 18 for(int i=1;i<=n;i++)a[i]=read(); 19 sort(a+1,a+n+1); 20 for(int i=1;i<=n;i++)c[i]=a[i]; 21 for(int i=n;i>=1;i--) 22 { 23 for(int j=30;j>=0;j--) 24 { 25 if(!(a[i]&(1<<j)))continue; 26 if(!p[j]){p[j]=a[i];break;} 27 a[i]^=p[j]; 28 } 29 if(!a[i])ans+=c[i]; 30 } 31 printf("%lld",ans); 32 return 0; 33 }