博弈論

BZOJ1188: [HNOI2007]分裂遊戲html

首先咱們能夠認爲每個石子都是一個獨立的遊戲(由於石子之間互不影響),那麼咱們用sg[i]表示處在i位置的一個石子的sg函數值,那麼咱們就能夠枚舉它的後繼狀態從而計算它的sg函數值。ide

最後累加ans便可。函數

 1 int v[100],sg[100],a[100];
 2 int main()
 3 {
 4     freopen("input.txt","r",stdin);
 5     freopen("output.txt","w",stdout);
 6     int T=read();
 7     while(T--)
 8     {
 9         int n=read();
10         sg[n-1]=0;
11         for3(i,n-2,0)
12          {
13              memset(v,0,sizeof(v));
14              for2(j,i+1,n-1)for2(k,j,n-1)v[sg[j]^sg[k]]=1;
15              for(sg[i]=0;v[sg[i]];sg[i]++);
16          }
17         int ans=0;
18         for0(i,n-1)
19         {
20             a[i]=read();
21             if(a[i]&1)ans^=sg[i];
22         }
23         if(!ans)printf("%d %d %d\n%d\n",-1,-1,-1,0);
24         else 
25         {
26             int tot=0;
27             for0(i,n-1)
28              for2(j,i+1,n-1)
29               for2(k,j,n-1)
30                if((ans^sg[i]^sg[j]^sg[k])==0)
31                 {
32                     if(!tot)printf("%d %d %d\n",i,j,k);
33                     tot++;
34                 }
35             printf("%d\n",tot);
36         }
37     }
38     return 0;
39 }
View Code

 

BZOJ1022: [SHOI2008]小約翰的遊戲Johnspa

取完最後一個石子者敗。先手必勝當且僅當:3d

1)存在某個a[i]>1,異或和!=0 code

2)不存在某個a[i]>1,異或和==0htm

腦補一下證實。不妨把狀態補全blog

 

3)存在某個a[i]>1,異或和==0遊戲

 

4)不存在某個a[i]>1,異或和!=0get

 

首先2)是必勝,4)是必敗

考慮1)的狀態,若是>1的a[i]只有一堆,咱們就可把他變成4)讓對手必敗。

不然咱們一定能夠變成3)

而對於3)狀況來講,必定存在至少兩個a[i]>1,而每次只能對一堆石子進行操做,操做完了以後的狀態必定是1)

我是在這裏看的:連接君

(好像出現了循環論證?QAQ)

 

 1 int main()
 2 {
 3     freopen("input.txt","r",stdin);
 4     freopen("output.txt","w",stdout);
 5     int T=read();
 6     while(T--)
 7     {
 8         int n=read(),ans=0,flag=0;
 9         for1(i,n){int x=read();if(x>1)flag=1;ans^=x;}
10         if((ans&&flag)||(!ans&&!flag))printf("%s\n","John");else printf("%s\n","Brother");
11     }
12     return 0;
13 }
View Code

 POJ1704Georgia and Bob

咱們發現每次給一個石子移動其實是給後一個石子增長了移動的範圍,也就是階梯nim中的把一堆 石子中的某些放到前一堆裏。因而階梯nim就能夠水過了!

 1 int a[maxn],b[maxn];
 2 int main()
 3 {
 4    freopen("input.txt","r",stdin);
 5    freopen("output.txt","w",stdout);
 6    int T=read();
 7    while(T--)
 8    {
 9         int n=read(),ans=0;
10         for1(i,n)a[i]=read();
11         sort(a+1,a+n+1);
12         for3(i,n-1,0)b[n-i]=a[i+1]-a[i]-1;
13         for1(i,n)if(i&1)ans^=b[i];
14         printf("%s\n",!ans?"Bob will win":"Georgia will win");
15    }
16    return 0;
17 }
View Code

 POJ2960S-Nim

暴力枚舉後繼狀態計算SG函數便可。

 1 int a[maxn],v[maxn],sg[maxn];
 2 int main()
 3 {
 4     freopen("input.txt","r",stdin);
 5     freopen("output.txt","w",stdout);
 6     while(1)
 7     {
 8         int n=read();if(!n)break;
 9         for1(i,n)a[i]=read();
10         sg[0]=0;
11         for1(i,10000)
12         {
13             for1(j,n)if(i>=a[j])v[sg[i-a[j]]]=1;
14             for(sg[i]=0;v[sg[i]];sg[i]++);
15             for1(j,n)if(i>=a[j])v[sg[i-a[j]]]=0;
16         }
17         int T=read();
18         while(T--)
19         {
20             int m=read(),ans=0;
21             for1(i,m)ans^=sg[read()];
22             printf("%c",ans?'W':'L');
23         }
24         printf("\n");
25     }            
26     return 0;
27 }
View Code

 POJ3537Crosses and Crosses

咱們發現若是取了中間i位置的石子,那麼後手必定 i-2到i+2都不能取了,這樣就分紅了兩個規模分別爲i-3和n-i-2的NIM遊戲。爆搜搞掉。

 1 int sg[maxn],v[maxn];
 2 int main()
 3 {
 4     freopen("input.txt","r",stdin);
 5     freopen("output.txt","w",stdout);
 6     int n=read();
 7     sg[0]=0;
 8     for1(i,n)
 9     {
10         for1(j,i)v[(j-3>=0?sg[j-3]:0)^(i-j-2>=0?sg[i-j-2]:0)]=1;
11         for(sg[i]=0;v[sg[i]];sg[i]++);
12         for1(j,i)v[(j-3>=0?sg[j-3]:0)^(i-j-2>=0?sg[i-j-2]:0)]=0;
13     }
14     printf("%d\n",sg[n]?1:2);
15     return 0;
16 }
View Code

 BZOJ2940: [Poi2000]條紋

sb題暴力sg。

 1 int a[3],sg[maxn],v[maxn];
 2 int main()
 3 {
 4     freopen("input.txt","r",stdin);
 5     freopen("output.txt","w",stdout);
 6     for0(i,2)a[i]=read();sort(a,a+3);
 7     for0(i,a[0]-1)sg[i]=0;
 8     for2(i,a[0],1000)
 9     {
10       for0(j,2)for1(k,i-a[j]+1)v[sg[k-1]^sg[i-k-a[j]+1]]=1;
11       for(sg[i]=0;v[sg[i]];sg[i]++);
12       for0(j,2)for1(k,i-a[j]+1)v[sg[k-1]^sg[i-k-a[j]+1]]=0;
13     }
14     int T=read();
15     while(T--)printf("%d\n",sg[read()]?1:2);
16     return 0;
17 }
View Code
相關文章
相關標籤/搜索