題意:2 個人玩游戲,給定一個數n,從 1 開始,輪流對數進行累乘一個數(2~9中取),
直到第一次等於或超過n為贏.
思路:1)找規律
如果n是 2 ~ 9 ,Stan 必勝。
如果輸入是 10~18 ,不管第一次Stan 乘的是什麼,Stan肯定在 2 ~ 9 之間,
無論stan乘以什麼,Ollie乘以大於1的數都都能超過 10 ~ 18 中的任何一個數。Ollie 必勝。
如果輸入是 19 ~ 162,那麼這個范圍是 Stan 的必勝態。
如果輸入是 163 ~ 324 ,這是又是Ollie的必勝態。
............
必勝態是有規律可循的。
如果"我方"首先給出了一個在n不斷除18後的得到不足18的
數m,"我方"就可以取得勝利,然而雙方都很聰明,所以這樣勝負就決定於n了,
如果n不斷除18後的得到不足18的數m,
若1<m<=9則先手勝利,
若9<m<=18則後手勝利.
[cpp]
#include<stdio.h>
int main()
{
double n;
while(scanf("%lf",&n)!=EOF)
{
while(n>18) n/=18;
printf(n<=9?"Stan wins.\n":"Ollie wins.\n");
}
return 0;
}
2)博弈(給出牛人的解題思路)
先引入必勝點和必敗點兩個概念:
必敗點(P點) :前一個選手(Previous player)將取勝的位置稱為必敗點。
必勝點(N點) :下一個選手(Next player)將取勝的位置稱為必勝點。
算法實現:
步驟1:將所有終結位置標記為必敗點(P點);(終結位置指的是不能將游戲進行下去的位置)
步驟2:將所有一步操作能進入必敗點(P點)的位置標記為必勝點(N點)
步驟3:如果從某個點開始的所有一步操作都只能進入必勝點(N點) ,則將該點標記為必敗點(P點) ;
步驟4:如果在步驟3未能找到新的必敗(P點),則算法終止;否則,返回到步驟2。
解題思路:
由於每次都是從p=1開始的,所以只要判斷每個游戲中1為必敗點還是必勝點即可。
(以下各式 / 均為取上整)依照上面所提到的算法,將終結位置,即[n,無窮]標記為必敗點;
然後將所有一步能到達此必敗段的點標記為必勝點,即[n/9,n-1]為必勝點;
然後將只能到達必勝點的點標記為必敗點,即[n/9/2,n/9-1]為必敗點;
重復上面2個步驟,直至可以確定1是必勝點還是必敗點。
[cpp]
#include <math.h>
#include <stdio.h>
int main()
{
unsigned int n,x;
while(~scanf("%u",&n))
{
for(x=0;n>1;x++)
{
if(x&1)
n = ceil(n*1.0/2);
else
n = ceil(n*1.0/9);
}
puts(x&1?"Stan wins.":"Ollie wins.");
}
return 0;
}