博弈论一点点
基本就是把這里的題過了一遍
SG函數資料(入門必備)
感覺很不錯的文章
博弈論(一):Nim游戲
博弈論(二):Sprague-Grundy函數
尋找必敗態——一類博弈問題的快速解法
練手
hdu1846
#include<cstdio>
using namespace std;
int main(){int T,n,m;scanf("%d",&T);while (T--){scanf("%d%d",&n,&m);if (n<=m)puts("first");//多余的一行 else puts((n%(m+1))?"first":"second");}return 0;
} hdu2147
#include<cstdio>
using namespace std;int main(){int n,m;while (scanf("%d%d",&n,&m)==2&&n&&m){puts((n&m&1)?"What a pity!":"Wonderful!");}return 0;
} hdu2188
#include<cstdio>
using namespace std;
int main(){int T,n,m;scanf("%d",&T);while (T--){scanf("%d%d",&n,&m);puts((n%(m+1))?"Grass":"Rabbit");}return 0;
} hdu2148
PN似乎反過來了。。。。找規律
#include<cstdio>
using namespace std;
int main(){int n,m;while (scanf("%d%d",&m,&n)==2){if (n>=m){for (int i=m;i<n;i++)printf("%d ",i);printf("%d\n",n);}else {int x=m%(n+1);if (x)printf("%d\n",x);else puts("none");}}return 0;
} Nim游戲
對于一個Nim游戲的局面(a1,a2,…,an),它是P-position當且僅當a1^a2^…^an=0,其中^表示異或(xor)運算。
先記個結論(坑以后再填)
hdu1907
#include<cstdio>
using namespace std;
int main(){int T,n,x;scanf("%d",&T);while (T--){scanf("%d",&n);int ans=0,cnt=0;for (int i=1;i<=n;i++){scanf("%d",&x);ans ^= x;if (x>1)cnt++;}if (!cnt)ans = !(n&1);if (ans)puts("John");else puts("Brother");}return 0;
} hdu2509
#include<cstdio>
#include<iostream>
using namespace std; int main(){int n,x;while (scanf("%d",&n)==1){int ans=0,cnt=0;for (;n--;){scanf("%d",&x);ans ^= x;if (x>1) cnt++;}if (!cnt)ans = !!(n&1);//這個時候n都=0了,前面循環應該for個i,這里能過是因為數據弱吧 if (ans)puts("Yes");else puts("No");}return 0;
} hdu1527
威佐夫博弈
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const double phi=(1+sqrt(5))/2.0;
int main(){int m,n;while (scanf("%d%d",&n,&m)==2){if (min(n,m)==(int)(phi*abs(n-m)))puts("0");else puts("1");}return 0;
} 繼續練手
hdu1847
#include<cstdio>
using namespace std;
int main(){int n;while (scanf("%d",&n)==1){if (n%3==0)puts("Cici");else puts("Kiki");}return 0;
} hdu1849
#include<cstdio>
using namespace std;
int main(){int n,x;while (scanf("%d",&n)==1&&n){int ans=0;for (;n--;){scanf("%d",&x);ans ^= x;}puts(ans?"Rabbit Win!":"Grass Win!");}return 0;
} hdu1850
#include<cstdio>
using namespace std;
const int N=111;
int a[N];
int main(){int n;while (~scanf("%d",&n)&&n){int nim=0;for (int i=1;i<=n;i++){scanf("%d",&a[i]);nim ^= a[i];}if (!nim)puts("0");else {int cnt=0;for (int i=1;i<=n;i++){int kk = nim^a[i];if (a[i]>kk)cnt++;}printf("%d\n",cnt);}}return 0;
} SG函數模板
理論詳細解釋
hdu1848
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1007;
int sg[N],fib[N];void getFib(){fib[1] = 1 , fib[2] = 2;for (int i=3;i<=17;i++)fib[i]=fib[i-1]+fib[i-2];
}void getSG(){getFib();/*memset(sg,0,sizeof(sg));int lastP;for (int i = 0; i < N ; i++ ){if (sg[i]==-1) sg[i] = i-lastP;else {//sg[i]==0lastP = i ;for (int j=1;j<17&&i+fib[j]<N;j++){sg[i+fib[j]] = -1 ;}}//printf("sg[%d]=%d\n",i,sg[i]);}*/int j;sg[0]=0;bool mex[17];for(int i=1;i<N;i++){memset(mex,0,sizeof(mex));for (j=1 ;fib[j]<=i ;j++ )mex[sg[i-fib[j]]]=1;for (j=0 ; j<N ; j++ )if(!mex[j])break;sg[i] = j;}}
//by cww97
int main(){int x,y,z;getSG();while (scanf("%d%d%d",&x,&y,&z)==3){if ( !x&& !y&& !z ) break;int ans = sg[x]^sg[y]^sg[z];if (ans)puts("Fibo");else puts("Nacci");}return 0;
} hdu1536
再次上演悲劇,調試N弄成了15,然后RTE,然后設成了10W(題目上數字看錯了),然后TLE,然后,,,,好氣啊
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=10007;
int s[110],sg[N],k;void getSG(){sg[0]=0;bool vis[N];for (int i=1;i<N;i++){memset(vis,0,sizeof(vis));for (int j=1;s[j]<=i&&j<=k;j++)vis[sg[i-s[j]]]=1;for (int j=0;j<N;j++)if(!vis[j]){sg[i]=j;break;}}
}int main(){//freopen("fuck.in","r",stdin);int m,n,x;while (scanf("%d",&k)==1&&k){for (int i=1;i<=k;i++)scanf("%d",&s[i]);sort(s+1,s+k+1);getSG();scanf("%d",&n);while (n--){scanf("%d",&m);int ans=0;while (m--){scanf("%d",&x);ans ^= sg[x];}putchar(ans?'W':'L');}puts("");}return 0;
} hdu5724
第一次多校訓練的題,,就是這題引出了這一整篇文fei章hua
學(zhuang)術(bi)一點的說法是,狀態壓縮+SG
先說狀態壓縮
簡單點的話,一行一行處理,第i個格子有棋子就 +1<< i(2的i次方) ,最后得到一個數字表示這一行的一種狀態,個人習慣從1開始數,,,于是1<<0=1遍沒有意義,導致我的表只有偶數(一半是空的,為了個人的強迫癥強行多開了一倍空間,不過我喜歡,嘻嘻),所以所有狀態的最小值是0(沒有棋子),最大是(1<<21-2)(所有格子都有棋子,等比數列求個和就行)。
SG嘛,對棋盤的每個狀態求sg值,注意所有棋子集中在右邊的時候是沒法走的(sg=0),所以從大到小求,,,狀態變化,我一開始寫的加減號,然后看有人用的位運算,以為自己錯了,改成位運算的樣子,A了之后又感覺自己想法不錯,改回加減號,果然還是A了,,當然,感覺用位運算更易于理(zhuang)解(bi)一點,這里貼的代碼就是位運算版本的辣(mdzz,一個符號講這么多廢話)
#include<cstdio>
#include<cstring>
using namespace std;
const int N=(1<<21)+7;
int sg[N];
int c[23],C;//the position of chessesint next(int x){//move the x-th chess for (int i=x;i<=C;i++){if (c[i+1]>c[i]+1)return 1<<(c[i]+1);}return 0;
}void getSG(){bool vis[107];// enough??for (int i=N-9;i>=0;i-=2){//downtoC=0; //get the stituationfor (int j=1;j<=20;j++)//num->arrayif (i&(1<<j)) c[++C]=j;c[C+1]=21;memset(vis,0,sizeof(vis));//sgsgsgfor (int j=1;j<=C;j++){int nxt=next(j);//move a chessif (nxt)vis[sg[i^(1<<c[j])^nxt]]=1;//- +}for (int j=0;j<107;j++)if(!vis[j]){sg[i]=j;break;}}
}int main(){//freopen("fuck.in","r",stdin);int T,n,m,x;getSG();scanf("%d",&T);while (T--){int ans = 0;scanf("%d",&n);for (;n--;){int che = 0;scanf("%d",&m);for (;m--;){scanf("%d",&x);che |= 1<<x;//+=}ans ^= sg[che];}if (ans)puts("YES");else puts("NO");}return 0;
}
轉載于:https://www.cnblogs.com/cww97/p/7533992.html
總結
- 上一篇: 一般做个鼻窦炎手术大概需要多少钱
- 下一篇: 易买网的一些增删改查