




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、(一)巴什博奕(Bash Game):只有一堆n個物品,兩個人輪流從這堆物品中取物,規(guī)定每次至少取一個,最多取m個。最后取光者得勝。 顯然,如果n=m+1,那么由于一次最多只能取m個,所以,無論先取者拿走多少個,后取者都能夠一次拿走剩余的物品,后者取勝。因此我們發(fā)現(xiàn)了如何取勝的法則:如果n=(m+1)r+s,(r為任意自然數(shù),sm),那么先取者要拿走s個物品,如果后取者拿走k(m)個,那么先取者再拿走m+1-k個,結果剩下(m+1)(r-1)個,以后保持這樣的取法,那么先取者肯定獲勝??傊3纸o對手留下(m+1)的倍數(shù),就能最后獲勝。
2、0; 這個游戲還可以有一種變相的玩法:兩個人輪流報數(shù),每次至少報一個,最多報十個,誰能報到100者勝。取石子(一)時間限制:3000 ms | 內存限制:65535 KB難度:2描述一天,TT在寢室閑著無聊,和同寢的人玩起了取石子游戲,而由于條件有限,他/她們是用旺仔小饅頭當作石子。游戲的規(guī)則是這樣的。設有一堆石子,數(shù)量為N(1<=N<=1000000),兩個人輪番取出其中的若干個,每次最多取M個(1<=M<=1000000),最先把石子取完者勝利。我們知道,TT和他/她的室友都十分的聰明,
3、那么如果是TT先取,他/她會取得游戲的勝利么?輸入第一行是一個正整數(shù)n表示有n組測試數(shù)據(jù)輸入有不到1000組數(shù)據(jù),每組數(shù)據(jù)一行,有兩個數(shù)N和M,之間用空格分隔。輸出對于每組數(shù)據(jù),輸出一行。如果先取的TT可以贏得游戲,則輸出“Win”,否則輸出“Lose”(引號不用輸出)樣例輸入21000 11 100樣例輸出LoseWin最優(yōu)解:#include<iostream>using namespace std;int main()int k;long m,n;cin>>k;while(k-)cin>>n>>m;if(n%(m+1)=0)cout<
4、<"Lose"<<endl;elsecout<<"Win"<<endl; 巴什博弈變形:有兩種解,依實際情況而定:取石子(七)時間限制:1000 ms | 內存限制:65535 KB難度:1描述Yougth和Hrdv玩一個游戲,拿出n個石子擺成一圈,Yougth和Hrdv分別從其中取石子,誰先取完者勝,每次可以從中取一個或者相鄰兩個,Hrdv先取,輸出勝利著的名字。輸入輸入包括多組測試數(shù)據(jù)。每組測試數(shù)據(jù)一個n,數(shù)據(jù)保證int范圍內。輸出輸出勝利者的名字。樣例輸入23樣例
5、輸出HrdvYougth解一:#include<cstdio>int n;int main() while(scanf("%d",&n) printf(n>=3?"Yougthn":"Hrdvn"); return 0;解二:3的倍數(shù)的是Yougth嬴#include<iostream>using namespace std;int main()int a;while(cin>>a)if(a%3!=0)cout<<"Hrdv"<<endl;e
6、lse cout<<"Yougth"<<endl;return 0; 尼姆博弈基本思想: 兩人從n堆物品中取任意個,先取完者勝。 即將n堆物品的數(shù)量異或,得到的值如果為0,則先手敗,反之先手勝。 如果要求先手在勝的條件下,到奇異局勢的方法數(shù),則判斷異或的值與每一堆原值異或后(結果應該表示該堆沒有參加異或
7、時的異或值)與原值比較大小,如果小于,則方法數(shù)加一。且對應的方法后,該堆的數(shù)目應變?yōu)楫惢虻闹蹬c每一堆原值異或的值。取石子(二)時間限制:3000 ms | 內存限制:65535 KB難度:5描述小王喜歡與同事玩一些小游戲,今天他們選擇了玩取石子。游戲規(guī)則如下:共有N堆石子,已知每堆中石子的數(shù)量,并且規(guī)定好每堆石子最多可以取的石子數(shù)(最少取1顆)。兩個人輪流取子,每次只能選擇N堆石子中的一堆,取一定數(shù)量的石子(最少取一個),并且取的石子數(shù)量不能多于該堆石子規(guī)定好的最多取子數(shù),等哪個人無法取子時就表示此人輸?shù)袅擞螒颉<僭O每次都是小王先取石子,并且游戲雙方
8、都絕對聰明,現(xiàn)在給你石子的堆數(shù)、每堆石子的數(shù)量和每堆石子規(guī)定的單次取子上限,請判斷出小王能否獲勝。輸入第一行是一個整數(shù)T表示測試數(shù)據(jù)的組數(shù)(T<100)每組測試數(shù)據(jù)的第一行是一個整數(shù)N(1<N<100),表示共有N堆石子,隨后的N行每行表示一堆石子,這N行中每行有兩個數(shù)整數(shù)m,n表示該堆石子共有m個石子,該堆石子每次最多取n個。(0<=m,n<=231)輸出對于每組測試數(shù)據(jù),輸出Win表示小王可以獲勝,輸出Lose表示小王必然會敗。樣例輸入211000 121 11 1樣例輸出LoseLose 提示注意下面一組測試數(shù)據(jù)21 1 2 2正確的結果應該是Wi
9、n因為小王會先從第二堆石子中取一個石子,使狀態(tài)變?yōu)? 11 2這種狀態(tài)下,無論對方怎么取,小王都能獲勝。最優(yōu)解#include<cstdio>int main()int T; scanf("%d",&T);while(T-)int m,n,g,sum=0;scanf("%d",&g);while(g-)scanf("%d%d",&m,&n);sum = m % (n + 1);puts(sum?"Win":"Lose"); 一般解:#include &
10、lt;iostream>using namespace std;#include <stdio.h>bool HandleEachCase();int main()int iCaseCount;cin>>iCaseCount;while(iCaseCount-)if(HandleEachCase()cout<<"Win"<<endl;elsecout<<"Lose"<<endl;bool HandleEachCase()long long magic= 0;long long
11、iCount;long long m, n;cin>>iCount;for(int i= 0; i< iCount; +i)cin>>m>>n;m%= (n+1);magic= m;return magic != 0;取石子(六)時間限制:1000 ms | 內存限制:65535 KB難度:3描述最近TopCoder的PIAOYI和HRDV很無聊,于是就想了一個游戲,游戲是這樣的:有n堆石子,兩個人輪流從其中某一堆中任意取走一定的石子,最后不能取的為輸家,注意: 每次只能從一堆取任意個,可以取完這堆
12、,但不能不取。假設PIAOYI先取石子,請你幫他判斷他是否能贏(假設他們取的過程中不發(fā)生失誤,他們足夠聰明)。輸入第一行輸入n,代表有n組測試數(shù)據(jù)(n<=10000)以下每組測試數(shù)據(jù)包含兩行:第一行:包含一個整數(shù)m,代表本組測試數(shù)據(jù)有m(m<=1000)堆石子;:第二行:包含m個整數(shù)Ai(Ai<=100),分別代表第i堆石子的數(shù)量。輸出若PIAOYI贏輸出“PIAOYI”,否則輸出“HRDV”注意每組結果占一行。樣例輸入321 133 8 1125 10最優(yōu)解:#include<iostream>#include<stdio.h>using names
13、pace std;void in(int &a)char ch;while(ch=getchar()<'0'|ch>'9');for(a=0;ch>='0'&&ch<='9'ch=getchar() a=a*10+ch-'0'int main()int T;in(T);while(T-)int n;in(n);int ans=0;for(int i=0;i!=n;+i)int b;in(b);ans=b;if(ans) puts("PIAOYI")
14、;else puts("HRDV");return 0; 取石子(三)時間限制:1000 ms | 內存限制:1000 KB難度:6描述小王喜歡與同事玩一些小游戲,今天他們選擇了玩取石子。游戲規(guī)則如下:共有N堆石子,已知每堆中石子的數(shù)量,兩個人輪流取子,每次只能選擇N堆石子中的一堆,取一定數(shù)量的石子(最少取一個),取過子之后,還可以將該堆石子中剩下的任意多個石子中隨意選取幾個放到其它的任意一堆或幾堆上。等哪個人無法取子時就表示此人輸?shù)袅擞螒?。注意,一堆石子沒有子之后,就不能再往此處放石子了。假設每次都是小王先取石子,并且游戲雙方都
15、絕對聰明,現(xiàn)在給你石子的堆數(shù)、每堆石子的數(shù)量,請判斷出小王能否獲勝。例如:如果最開始有4堆石子,石子個數(shù)分別為3 1 4 2,而小王想決定要先拿走第三堆石子中的兩個石子(石子堆狀態(tài)變?yōu)? 1 2 2),然后他可以使石子堆達到的狀態(tài)有以下幾種:3 1 2 2(不再移動石子)4 1 1 2(移動到第一堆一個)3 2 1 2(移動到第二堆一個)3 1 1 3(移動到第四堆一個)5 1 0 2(全部移動到第一堆)3 3 0 2(全部移動到第二堆)3 1 0 4(全部移動到最后)輸入可能有多組測試數(shù)據(jù)(測試數(shù)據(jù)組數(shù)不超過1000)每組測試數(shù)據(jù)的第一行是一個整數(shù),表示N(1<=N<=10)第二
16、行是N個整數(shù)分別表示該堆石子中石子的數(shù)量。(每堆石子數(shù)目不超過100)當輸入的N為0時,表示輸入結束輸出對于每組測試數(shù)據(jù),輸出Win表示小王可以獲勝,輸出Lose表示小王必然會敗。樣例輸入32 1 321 10樣例輸出WinLose一般解:#include <iostream>#include <cstring>#include <cstdlib>using namespace std;bool HandleEachCase();int main()while(HandleEachCase()/empty whilebool HandleEachCase()
17、int iCount;int count101;memset(count, 0, sizeof(count);cin>>iCount;if(!iCount)return false;int iStone;for(int i= 0; i< iCount; +i)cin>>iStone;+countiStone;int magic = 0;for(int i= 0; i< 101 && !magic; +i)magic+= counti&1;if(magic)cout<<"Win"<<endl;
18、elsecout<<"Lose"<<endl;return true;分析:顯然,如果石頭是能夠兩兩配對,每一對的數(shù)目相同,比如:2,3,2,4可以配對成(2,2),(4,4) ,這樣的話就是先拿的輸,因為后拿的可以使自己拿完后仍然能夠使得兩兩配對,且每一對的數(shù)目相同.剛剛開始的時候,如果已經(jīng)兩兩配對了,那么先拿的輸了,否則,選拿的可以把最大的動一下手腳,使剩下的兩兩配對,且每一對的數(shù)目相同.最優(yōu)解:#include<iostream>#include<cstring>using namespace std;bool ok(i
19、nt stone)for(int i=0;i!=110;i+)if(stonei&1) return true;return false;int main()int stone110;int n,m;while(cin>>n && n)memset(stone,0,sizeof(stone);while(n-)cin>>m;stonem+;cout<<(ok(stone)?"Win":"Lose")<<endl; 威佐夫博奕(Wythoff Game):有兩堆各若干個物品,兩個人輪流
20、從某一堆或同時從兩堆中取同樣多的物品,規(guī)定每次至少取一個,多者不限,最后取光者得勝。 這種情況下是頗為復雜的。我們用(ak,bk)(ak bk ,k=0,1,2,.,n)表示兩堆物品的數(shù)量并稱其為局勢,如果甲面對(0,0),那么甲已經(jīng)輸了,這種局勢我們稱為奇異局勢。前幾個奇異局勢是:(0,0)、(1,2)、(3,5)、(4,7)、(6,10)、(8,13)、(9,15)、(11,18)、(12,20)。 可以看出,a0=b0=0,ak是未在前面出現(xiàn)過的最小自然數(shù),而 bk= ak + k,奇異局勢有
21、如下三條性質: 1。任何自然數(shù)都包含在一個且僅有一個奇異局勢中。 由于ak是未在前面出現(xiàn)過的最小自然數(shù),所以有ak > ak-1 ,而 bk= ak + k > ak-1 + k-1 = bk-1 > ak-1 。所以性質1。成立。 2。任意操作都可將奇異局勢變?yōu)榉瞧娈惥謩荨?#160; 事實上,若只改變奇異局勢(ak,bk)的某一個分量,那么另一個分量不可能在其他奇異局勢中,所以必然是非奇異局勢。
22、如果使(ak,bk)的兩個分量同時減少,則由于其差不變,且不可能是其他奇異局勢的差,因此也是非奇異局勢。 3。采用適當?shù)姆椒?,可以將非奇異局勢變?yōu)槠娈惥謩荨?#160; 假設面對的局勢是(a,b),若 b = a,則同時從兩堆中取走 a 個物體,就變?yōu)榱似娈惥謩荩?,0);如果a = ak ,b > bk,那么,取走b - bk個物體,即變?yōu)槠娈惥謩?;如?a = ak , b < bk ,則同時從兩堆中拿走 ak - ab - ak個物體,變?yōu)槠娈惥?/p>
23、勢( ab - ak , ab - ak+ b - ak);如果a > ak ,b= ak + k,則從第一堆中拿走多余的數(shù)量a - ak 即可;如果a < ak ,b= ak + k,分兩種情況,第一種,a=aj (j < k),從第二堆里面拿走 b - bj 即可;第二種,a=bj (j < k),從第二堆里面拿走 b - aj 即可。 從如上性質可知,兩個人如果都采用正確操作,那么面對非奇異局勢,先拿者必勝;反之,則后拿者取勝。 那么任給一個局勢(a,b),怎樣判斷它是
24、不是奇異局勢呢?我們有如下公式: ak =k(1+5)/2,bk= ak + k (k=0,1,2,.,n 方括號表示取整函數(shù))奇妙的是其中出現(xiàn)了黃金分割數(shù)(1+5)/2 = 1。618.,因此,由ak,bk組成的矩形近似為黃金矩形,由于2/(1+5)=(5-1)/2,可以先求出j=a(5-1)/2,若a=j(1+5)/2,那么a = aj,bj = aj + j,若不等于,那么a = aj+1,bj+1 = aj+1+ j + 1,若都不是,那么就不是奇異局勢。然后再按照上述法則進行,一定會遇到奇異局勢。取石子 (四)時
25、間限制:1000 ms | 內存限制:65535 KB難度:4描述有兩堆石子,數(shù)量任意,可以不同。游戲開始由兩個人輪流取石子。游戲規(guī)定,每次有兩種不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在兩堆中同時取走相同數(shù)量的石子。最后把石子全部取完者為勝者?,F(xiàn)在給出初始的兩堆石子的數(shù)目,如果輪到你先取,假設雙方都采取最好的策略,問最后你是勝者還是敗者。輸入輸入包含若干行,表示若干種石子的初始情況,其中每一行包含兩個非負整數(shù)a和b,表示兩堆石子的數(shù)目,a和b都不大于1,000,000,000。輸出輸出對應也有若干行,每行包含一個數(shù)字1或0,如果
26、最后你是勝者,則為1,反之,則為0。樣例輸入2 18 44 7樣例輸出010最優(yōu)解:#include <iostream>#include <cmath> using namespace std; int main() int m,n;while(cin>>m>>n)if (m > n)int temp;temp = m;m = n;n =temp;int k = n - m;int data = floor(k*(1.0+sqrt(5.0)/2.0);if (data = m)cout<<0<<endl;elsec
27、out<<1<<endl; Wythoff Game時間限制:1000 ms | 內存限制:65535 KB難度:1描述最近ZKC同學在學博弈,學到了一個偉大的博弈問題-威佐夫博弈。相信大家都學過了吧?沒學過?沒問題。我將要為你講述一下這個偉大的博弈問題。有兩堆石子,數(shù)量任意,可以不同。游戲開始由兩個人輪流取石子。游戲規(guī)定,每次有兩種不同的取法:一是可以在任意的一堆中取走任意多的石子;二是可以在兩堆中同時取走相同數(shù)量的石子。最后把石子全部取完者為勝者。我們今天要做的是求前n個必敗態(tài)。什么是必敗態(tài)?比如我們把(a,b)稱為一種狀
28、態(tài),a,b分別為兩堆石子中所剩的數(shù)目。如果a=0,b=0,我們說該種狀態(tài)為必敗態(tài),因為我不能再進行游戲,即使是可以進行,那也是必敗的,你知道,游戲的我們都是非常聰明的。(0,0)(1,2)(3,5).都是必敗態(tài),我們今天要做的就是求前n個必敗態(tài)。不會?好吧!我再告訴你:假設第n個必敗態(tài)為(a,b)a為前n-1個必敗態(tài)中沒有出現(xiàn)的最小自然數(shù),b=a+n。這下大家應該明白了吧。好吧,我們的任務就的要前n個必敗態(tài)。規(guī)定第0個必敗態(tài)為(0,0)。輸入多組數(shù)據(jù)。輸入為一個數(shù)n(0<=n<=100000)。輸出按照要求求出前n個必敗態(tài)。輸出格式看下面樣例。樣例輸入31樣例輸出(0,0)(1,2
29、)(3,5)(4,7)(0,0)(1,2)提示注意:每種情況中間沒有空格#include<stdio.h>#include<math.h>typedef struct Nodeint a,b;N;N res100001;void init()res0.a=0;res0.b=0;for(int i=1;i<100001;i+)resi.a=(1+sqrt(5)*i/2;resi.b=resi.a+i;int main()int n;init();while(scanf("%d",&n)!=EOF)for(int i=0;i<=n;i
30、+)printf("(%d,%d)",resi.a,resi.b);printf("n");return 0; 本人自己寫的代碼:#include<stdio.h>int main()int n,k,b,a100001,i,m=0;a0=0;while(scanf("%d",&n)if(n<=m)for(k=0;k<=n;k+)printf("(%d,%d)",ak,ak+k);elseprintf("(%d,%d)",a0,a0);for(k=1;k<=n
31、;k+)b=ak-1+1;for(i=k-1;i>=0;i-)if(b=(ai+i)b+;else if(b>(ai+i)break;ak=b;printf("(%d,%d)",ak,ak+k);m=n;printf("n");return 0; 取石子(八)時間限制:1000 ms | 內存限制:65535 KB難度:3描述有兩堆石子,數(shù)量任意,可以不同。游戲開始由兩個人輪流取石子。游戲規(guī)定,每次有兩種不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在兩堆中同時取走相同數(shù)量的石子。最后
32、把石子全部取完者為勝者?,F(xiàn)在給出初始的兩堆石子的數(shù)目,如果輪到你先取,假設雙方都采取最好的策略,問最后你是勝者還是敗者。如果你勝,你第1次怎樣取子? 輸入輸入包含若干行,表示若干種石子的初始情況,其中每一行包含兩個非負整數(shù)a和b,表示兩堆石子的數(shù)目,a和b都不大于1,000,000。a=b=0退出。輸出輸出也有若干行,如果最后你是敗者,則為0,反之,輸出1,并輸出使你勝的你第1次取石子后剩下的兩堆石子的數(shù)量x,y,x<=y。如果在任意的一堆中取走石子能勝同時在兩堆中同時取走相同數(shù)量的石子也能勝,先輸出取走相同數(shù)量的石子的情況,假如取一堆的有多種情況,先輸出從石子多的一堆中取的情
33、況,且要求輸出結果保證第二個值不小于第一個值。樣例輸入1 2 5 72 20 0樣例輸出013 53 54 710 01 2最優(yōu)解:#include<iostream>#include <cstdio>#include <algorithm>#include<math.h>using namespace std;int main() int a,b,temp,temp2,k,i; while(scanf("%d%d",&a,&b),a+b) if(a>b) swap(a,b); k=b-a; temp=k
34、*(1.0+sqrt(5.0)/2.0; if(a=temp) /奇異局勢 printf("0n"); else printf("1n"); if(abs(temp-a)=abs(temp+k-b)&&temp<a) /兩堆 printf("%d %dn",temp,temp+k); if(a=0) /0 0情況,第一種奇異局勢 printf("0 0n"); for(i=1;i<=b;i+) /一堆 temp=i*(1.0+sqrt(5.0)/2.0; temp2=temp+i; if
35、(temp>b) break; if(temp=a&&temp2<b) printf("%d %dn",a,temp2); else if(temp2=a&&temp<b) printf("%d %dn",temp,a); else if(temp2=b&&temp<a) printf("%d %dn",temp,b); return 0; Fibonaccis Game(斐波那契博弈)斐波那契博弈模型,大致上是這樣的:有一堆個數(shù)為 n 的石子,游戲雙方輪流取石子
36、,滿足:1. 先手不能在第一次把所有的石子取完;2. 之后每次可以取的石子數(shù)介于1到對手剛取的石子數(shù)的2倍之間(包含1和對手剛取的石子數(shù)的2倍)。約定取走最后一個石子的人為贏家,求必敗態(tài)。 (轉)分析: n = 2時輸出second; n = 3時也是輸出second; n = 4時,第一個人想獲勝就必須先拿1個,這時剩余的石子數(shù)為3,此時無論第二個人如何取,第一個人都能贏,輸出first; n = 5時,first不可能獲勝,因
37、為他取2時,second直接取掉剩下的3個就會獲勝,當他取1時,這樣就變成了n為4的情形,所以輸出的是second; n = 6時,first只要去掉1個,就可以讓局勢變成n為5的情形,所以輸出的是first; n = 7時,first取掉2個,局勢變成n為5的情形,故first贏,所以輸出的是first; n = 8時,當first取1的時候,局勢變?yōu)?的情形,第二個人可贏,first取2的時候,局勢變成n為6得到情形,也是第
38、二個人贏,取3的時候,second直接取掉剩下的5個,所以n = 8時,輸出的是second; 從上面的分析可以看出,n為2、3、5、8時,這些都是輸出second,即必敗點,仔細的人會發(fā)現(xiàn)這些滿足斐波那契數(shù)的規(guī)律,可以推斷13也是一個必敗點。 借助“Zeckendorf定理”(齊肯多夫定理):任何正整數(shù)可以表示為若干個不連續(xù)的Fibonacci數(shù)之和。n=12時,只要誰能使石子剩下8且此次取子沒超過3就
39、能獲勝。因此可以把12看成8+4,把8看成一個站,等價與對4進行"氣喘操作"。又如13,13=8+5,5本來就是必敗態(tài),得出13也是必敗態(tài)。也就是說,只要是斐波那契數(shù),都是必敗點。所以我們可以利用斐波那契數(shù)的公式:fibi = fibi-1 + fibi-2,只要n是斐波那契數(shù)就輸出No。取石子(五)時間限制:1000 ms | 內存限制:65535 KB難度:4描述himdd最近很想玩游戲,于是他找到acmj和他一起玩,游戲是這樣的:有一堆石子,兩個人輪流從其中取走一定的石子,取走最后所有石子的人為贏家,不過得遵循如下規(guī)則:1.
40、第一次取不能取完,至少取1顆.2.從第二次開始,每個人取的石子數(shù)至少為1,至多為對手剛取的石子數(shù)的兩倍。himdd事先想知道自己會不會贏,你能幫幫他嗎?(每次himdd先手)輸入有多組測試數(shù)據(jù),每組有一個整數(shù)n(2<=n<264);輸出himdd會贏輸出Yes,否則輸出No;樣例輸入256樣例輸出NoNoYes一般解:#include<iostream>using namespace std;int main() long long n,fib100; int i,flag; fib0=2; fib1=3; for(i=2;i<100;i+) fibi=fibi-
41、1+fibi-2; while(cin>>n&&n) flag=0; for(i=0;i<100;i+) if(fibi=n) cout<<"Non" flag=1; break; if(flag=0) cout<<"Yesn" return 0;Nim Staircase博奕:這個問題是尼姆博弈的拓展:游戲開始時有許多硬幣任意分布在樓梯上,共n階樓梯從地面由下向上編號為0到n。游戲者在每次操作時可以將樓梯j(1<=j<=n)上的任意多但至少一個硬幣移動到樓梯j-1上。游戲者輪流操作,
42、將最后一枚硬幣移至地上(0號)的人獲勝。算法:將奇數(shù)樓層的狀態(tài)異或,和為0則先手必敗,否則先手必勝。證明略。例題:Poj1704這道題可以把兩個棋子中間間隔的空格子個數(shù)作為一堆石子,則原題轉化為每次可以把左邊的一堆石子移到相鄰的右邊的一堆中。也就是階梯尼姆博弈,注意對輸入數(shù)據(jù)先排序,然后倒著往前數(shù)(an-an-1-1為第一個),奇數(shù)個數(shù)到的就做一下xor,其中最前面的看做a1-0-1,參考程序:vart,n,b,i,j:longint;a:array0.1000of longint;beginreadln(t);repeatdec(t);readln(n);for i:=1 to n do r
43、ead(ai);qsort(1,n);/快排略j:=0;b:=0;for i:=n downto 1 dobegininc(j);if odd(j) then b:=b xor (ai-ai-1-1);end;if b=0 then writeln('Bob will win') else writeln('Georgia will win');until t=0;end.SG函數(shù)模板首先定義mex(minimal excludant)運算,這是施加于一個集合的運算,表示最小的不屬于這個集合的非負整數(shù)。例如mex0,1,2,4=3、mex2,3,5=0、mex=
44、0。對于一個給定的有向無環(huán)圖,定義關于圖的每個頂點的Sprague-Grundy函數(shù)g如下:g(x)=mex g(y) | y是x的后繼 ,這里的g(x)即sgx例如:取石子問題,有1堆n個的石子,每次只能取1,3,4個石子,先取完石子者勝利,那么各個數(shù)的SG值為多少?sg0=0,f=1,3,4,x=1時,可以取走1-f1個石子,剩余0個,mexsg0=0,故sg1=1;x=2時,可以取走2-f1個石子,剩余1個,mexsg1=1,故sg2=0;x=3時,可以取走3-f1,3個石子,剩余2,0個,mexsg2,sg0=0,0,故sg3=1;x=4時,可以取走4-f1,3,4個石子,剩余3,1,
45、0個,mexsg3,sg1,sg0=1,1,0,故sg4=2;x=5時,可以取走5-f1,3,4個石子,剩余4,2,1個,mexsg4,sg2,sg1=2,0,1,故sg5=3;以此類推.x 0 1 2 3 4 5 6 7 8.sgx 0 1 0 1 2 3 2 0 1.計算從1-n范圍內的SG值。f(存儲可以走的步數(shù),f0表示可以有多少種走法)f需要從小到大排序,這個模版f是從1開始的。hash數(shù)組大小跟f大小差不多1.可選步數(shù)為1m的連續(xù)整數(shù),直接取模即可,SG(x) = x % (m+1);2.可選步數(shù)為任意步,SG(x) = x; 3. 可選步數(shù)為一系列不連續(xù)的數(shù),用GetSG()計算
46、/f:可以取走的石子個數(shù)/sg:0n的SG函數(shù)值/hash:mexint fN,sgN,hashN; void getSG(int n) int i,j; memset(sg,0,sizeof(sg); for(i=1;i<=n;i+) memset(hash,0,sizeof(hash); for(j=1;fj<=i;j+) hashsgi-fj=1; for(j=0;j<=n;j+) /求mes中未出現(xiàn)的最小的非負整數(shù) if(hashj=0) sgi=j; break; 下邊補充一點東西。上邊那個模版求hash時候并沒有考慮fj有效長度,在某些題目中可以通過,比如這個。因
47、為在求斐波那契數(shù)列時候肯定多求了一個,而就是因為這個會在求hash時候打破循環(huán)。其實總的來說還是這個函數(shù)并不嚴密。因為有的時候f是有有效長度的,如果多出了這個長度就會出現(xiàn)錯誤,如果你的初值都是0,那么就會取到0,如果是-1,那么就會取到-1,肯定不對。比如這個題。下面這兩個模版應該就比較嚴密了,這個里邊的f是從零開始的。轉自:1、 sg打表/f:可以取走的石子個數(shù) /sg:0n的SG函數(shù)值 /hash:mex int fK,sgN,hashN; void getSG(int n) memset(sg,0,sizeof(sg); for(int i=1; i<=n; i+) memset(
48、hash,0,sizeof(hash); for(int j=0; fj<=i && j < k; j+) /k是f的有效長度 hashsgi-fj=1; for(int j=0; ; j+) /求mes中未出現(xiàn)的最小的非負整數(shù) if(hashj=0) sgi=j; break; 2、 Dfs/注意 S數(shù)組要按從小到大排序 SG函數(shù)要初始化為-1 對于每個集合只需初始化1遍 /n是集合s的大小 Si是定義的特殊取法規(guī)則的數(shù)組 int sN,sgN,n; int getSG(int x) if(sgx!=-1) return sgx; bool visM; memse
49、t(vis,0,sizeof(vis); for(int i=0; i<n; i+) if(x>=si) visgetSG(x-si)=1; for(i=0; i+) if(!visi) sgx=i; break; return sgx; 博弈問題之SG函數(shù)博弈小結2013-09-05 09:11:30 我來說兩句 作者:Bright-xl 收藏 我要投稿SG函數(shù):給定一個有向無環(huán)圖和一個起始頂點上的一枚棋子,兩名選手交替的將這枚棋子沿有向邊進行移動,無法移 動者判負。事實上,這個游戲可以認為是所有Impartial Combinatorial Games的抽象模型。也就是說,任何
50、一個ICG都可以通過把每個局面看成一個頂點,對每個局面和它的子局面連一條有向邊來抽象成這個“有向圖游戲”。下 面我們就在有向無環(huán)圖的頂點上定義Sprague-Garundy函數(shù)。首先定義mex(minimal excludant)運算,這是施加于一個集合的運算,表示最小的不屬于這個集合的非負整數(shù)。例如mex0,1,2,4=3、mex2,3,5=0、mex=0。在我的理解中,sg函數(shù)就是一個對有向無環(huán)圖dfs的過程,在處理nim博弈時,多個石堆可以看成多個sg函數(shù)值的異或。例題:POJ2311 Cutting Game典型的sg博弈,找后繼狀態(tài)。題意是給出一個n*m的紙片,每次剪成兩部分,誰先剪
51、到1*1就勝利。這就是一個找后繼的題目,每次剪成的兩部分就是前一狀態(tài)的后繼,只要將兩個部分的sg值異或起來就是前一狀態(tài)的sg值。cpp #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<set> #include<vector> #include<stack> #define mem(a,b) memset(a,b,sizeof(a) #define FOR(a,b,i) for(i=a;i<=b;+i) #define For(a,b,i) for(i=a;i<b;+i) #define N 1000000007 using namespace std; inline void RD(int &ret) char c; do c=getchar(); while(c<'0'|c>'9'); ret=c-'0
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 影視器材租賃合同
- 度招生代理合同書
- 反擔保合同格式及范例
- 農(nóng)村土地買賣合同書樣本
- 國際工程合作開發(fā)合同
- 新一代虛擬現(xiàn)實體驗設備租賃合同2025
- 室內窗簾定制合同
- 國際貿易代理合同(七)
- 挖機購銷合同范本
- 健身房會員權益轉讓合同
- 綜述的寫作方法與技巧課件
- 零售藥店實施GSP情況的內審報告
- 機械設計基礎網(wǎng)考題庫答案 吉林大學
- 新蘇教版科學六年級下冊全冊教案(含反思)
- 觸電事故應急處置卡
- 國際貿易運輸方式課件
- 南陽理工學院畢業(yè)論文格式規(guī)范
- SolidWorks入門教程(很全面)PPT課件
- 日語五十音圖(清晰打印版)92905
- 新舊會計科目對照表
- 2019寧波地產(chǎn)品牌半程馬拉松 (海景風情 健康寧波主題)活動策劃方案-41P
評論
0/150
提交評論