2 石頭遊戲(坑爹)

2021-08-30 10:55:56 字數 2417 閱讀 3093

題目抽象:

一堆石子兩個人輪流取,每次至少要取走乙個。先取的人第一次可以取任意多個,但是不能全部取完。之後每個人取石子時,能取的數目最多不能超過對手剛才取的石子數的k倍(k為給定常量)。取走最後乙個石子的人算贏。

在兩個人都以最優策略進行遊戲時,先手要麼必勝要麼必負,必勝還是必負取決於一開始有多少個石子,本題就是告訴你開始的石子數目,你需要判斷先手必勝還是先手必負,然後對先手必勝的情況,要算出先手一方第一次至少需要取多少顆石子。

解題思路:

首先根據提示我們可以知道先手負的局面都是一些特殊局面,並且數量遠少於先手勝的局面,因此分析主要針對先手負的局面進行,提示中的資訊給了乙個很好的入手點,我們先對k=1時的性質進行分析:

先手負的初始石子數序列為,通過觀察規模比較小的資料不難發現,若初始石子數n不是2的冪,則取石子數最少的必勝走法恰是n用二進位制表示時最後乙個1所代表的數值,比如n用二進位制數表示是11011010時,必勝取法為2(10)。先手取走這「最後乙個1」之後,由於k=1,後手取的石子數至多和先手一樣多,所以後手無法取走剩下的石子中的「最後乙個1」,假如我們能證明後手取完之後先手仍然能取走剩下石子中的「最後乙個1」,那麼我們就證明了只要一直取走「最後乙個1」,先手就能夠保證取勝。事實上對於2^p以及任意乙個滿足x<2^p的正整數x,2^p-x用二進位制表示時的「最後乙個1」代表的數值必然不大於x,於是,只要有一方無法取完當前石子數的「最後乙個1」,另一方就一定可以取走剩下石子數的「最後乙個1」,因此,在初始石子為2的冪時,先手無法取走「最後乙個1」(第一次無法取走全部石子),勝利就屬於對方啦,而只要初始石子數不是2的冪,先手就能保證勝利。

然後分析k=2時的情形:

先手負的初始石子數序列為,正好是fibonacci數列,而觀察小規模資料可以發現,先手取勝時取走的最少石子數也是fibonacci數列中的數。對於fibonacci數列,有以下性質:

性質1:任何乙個正整數都可以分解為fibonacci數列中一些不相鄰的數的和,且分解方法唯一。且這些數滿足2fk1例如:前1個數有1種取法,即:

前2個數有2種取法,即:,

前3個數有4種取法,即:,,,

前4個數有7種取法,即:,,,,,,

前n個數的取法為:《前n-1個數的所有取法》,,

性質2:k=2時,如果初始石子數n不是fibonacci數,則可以把n分解為一些不相鄰的fibonacci數的和,在該分解方案裡的最小的數,即是取石子數最少的獲勝方法。

#include

#define maxm 1000000

int n,k;

int a[maxm+1];//記錄fibonacci數列的前幾個數

int r[maxm+1];//記錄上述前幾個數的至多取法

void solve()//優秀的男人總是堅持到了最關鍵的乙個函式

int i,j;

a[0]=0;

r[0]=0;

for(i=1,j=0;ia[i]=r[i-1]+1;//這裡也是直接觀察前面的性質1得到的

while(j+1j++;//使j變為i-2

r[i]=a[i]+r[j];//這裡也是由性質一的來推導出來,其實就是r(n)=r(n-1)+1+r(n-2)

if(a[i]>=n)  break;//對a陣列的要求只要達到fibonacci數列中的某乙個數就行,這個數必須大於或者等於此時石子數

if(i>maxm)//避免石子數太多,這樣就不好玩了

printf("un solvable\n");//就是吊,老子不玩了

return;

if (a[i]=n)//如果石子數剛好滿足fibonacci數列中的數的話,那沒辦法了,先手必輸

printf("lose\n");

return;

for(;i>=1;i--)//進行到這一步時就說明此時的a[i]>n的,也就是先手必勝,所以按從大到小的順序從n中減去fibonacci數列中if(n==a[i])//這就是最後一步,通過下面的相減,得到結果與fibonacci數列中的數相等,也就是先手勝時第一手應該取出多少石子

printf("%d\n",n);

return;

else if (n>a[i])//這裡分別減去fibonacci數列中小於n的值,直到後期滿足n==a[i]

n-=a[i];

printf("logic error\n");//來自一種神秘的意外,莫名其妙的錯誤,編譯器的錯

int main()

int ca,cc=0;

scanf("%d",&ca);//總共進行多少次實驗

while(ca-->0)

scanf("%d %d",&n,&k);//其中n表示石子數,k表示題目中給定常量

printf("case %d:",++cc);

solve();//這裡進行先手必勝或者必負的判斷,首先判斷n是否在fibonacci數列中,在的話,就先手必負,輸出lose,否則,按從大到小的順序從n中減去fibonacci數列中return 0;

2973 石頭遊戲

給出乙個方格陣,初始每個格仔中都沒有石頭,然後每個格仔都有乙個操作序列,並且每時刻執行乙個,迴圈執行,序列長度小於等於6,問t時刻後石頭個數最多的格仔中有幾個石頭。因為操作序列長度小於等於6,所以每60次操作必有一次迴圈,所以可以對60次操作建乙個矩陣,由60次操作相乘,矩陣的長寬均為方格矩陣的元素...

877 石頭遊戲

亞歷克斯和李用幾堆石子在做遊戲。偶數堆石子排成一行,每堆都有正整數顆石子piles i 遊戲以誰手中的石子最多來決出勝負。石子的總數是奇數,所以沒有平局。亞歷克斯和李輪流進行,亞歷克斯先開始。每回合,玩家從行的開始或結束處取走整堆石頭。這種情況一直持續到沒有更多的石子堆為止,此時手中石子最多的玩家獲...

11 石頭 剪刀 布遊戲

bin bash 編寫指令碼,實現人機 石頭,剪刀,布 遊戲 game 石頭 剪刀 布 num random 3 computer 通過隨機數獲取計算機的出拳 出拳的可能性儲存在乙個陣列中,game 0 game 1 game 2 分別是 3 中不同的可能 echo 請根據下列提示選擇您的出拳手勢 ...