【算法总结】博弈论相关

〖相关资料

博弈论 SG函数

〖相关题目

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

  

posted @ 2018-04-19 20:45  Zsnuo  阅读(192)  评论(0编辑  收藏  举报