看了看《挑戰程序設計競賽》的4.2博弈方便的知識點。
感覺也真是聰明啊……
整理整理,鍛鍊大腦~
1】Alice和Bob在玩這樣一個遊戲:給定k個數字a1,a2…ak。一開始,有x個石子,Alice和Bob輪流取石子。每次所取石子的個數一定要在a1~ak中。Alice先取。取走最後一個石子的一方獲勝。當雙方都採取最優策略時,誰會獲勝?題目假定a1~ak中一定有1.
分析題目,有三種情況:
1.沒有剩餘,也就是只剩下了0個,那麼必敗
2.對於某個i(1<=i<=k),j-A[i]必敗那麼j就是必勝(可以從剩下的j中拿去A[i],達到對方的必敗狀態)
3.對於某個i(1<=i<=k),j-A[i]必勝那麼j就是必敗(對方可以從剩下的j中拿去A[i])
建立一個win[j]數組,表示輪到玩家拿的時候剩餘j時的勝負狀態。
#include <cstdio>
#define maxn 105
int X,K,A[maxn];
bool win[maxn];
void slove(){
win[0]=false;
for(int j=1;j<=X;j++){
//如果對手達到必敗,那麼必勝
win[j]=false;
/*三種都可
for(int i=0;i<K;i++){ //如果可取的A[i]<=剩餘的j,進入判斷
win[j] |= ( A[i]<=j && !win[j-A[i]]);
}
for(int i=0;i<K&&A[i]<=j;i++){
win[j] |= !win[j-A[i]] ;
}
*/
for(int i=0;i<K&&A[i]<=j;i++){
if(!win[j-A[i]])
win[j] |=true ;
}
}
if(win[X]) puts("Alice");
else puts("Bob");
}
int main() {
scanf("%d%d",&X,&K);
for(int i=0;i<K;i++){
scanf("%d",&A[i]);
}
slove();
return 0;
}
2】POJ2484
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 4824 | Accepted: 2997 |
Description
Figure 1
Note: For n > 3, we use c1, c2, ..., cn to denote the coins clockwise and if Alice remove c2, then c1 and c3 are NOT adjacent! (Because there is an empty place between c1 and c3.)
Suppose that both Alice and Bob do their best in the game.
You are to write a program to determine who will finally win the game.
Input
Output
Sample Input
1 2 3 0
Sample Output
Alice Alice Bob
n枚硬幣排成一個圈,
Alice和Bob輪流從中取1~2枚硬幣,取得2枚硬幣要相連,取走最後一枚硬幣獲勝。雙方採取最優策略,誰會獲勝?
如果兩個人取硬幣的的狀態一樣(中間不連續),則是一種必敗狀態。
A取硬幣,B取可以達到 和A同樣狀態的 硬幣,那麼B必勝。
所以,Alice在第一步取了1枚或者2枚硬幣之後,原本成圈的硬幣編程了長度爲n-1或者n-2的鏈,
只要B在中間位置根據奇偶性取走硬幣就可以把硬幣扽成長度相同的鏈。
然後A就必敗了…
當然除了N<=2的情況。
好吧,思維繞一點,但是想清楚了,代碼一下就出來…所以這種題考的實際就是智商…多做多看~…
#incldue <cstdio>
int main(){
int n;
scanf("%d",&n);
if(n<+2) puts("Alice");
else puts("Bob");
return 0;
}
3.Poj2348
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 8594 | Accepted: 3500 |
Description
25 7 11 7 4 7 4 3 1 3 1 0
an Stan wins.
Input
Output
Sample Input
34 12 15 24 0 0
Sample Output
Stan wins Ollie wins
輾轉相除博弈遊戲
預處理:
1.先調整使得a<b
2.若b%a==0 必勝
判斷:
1】.b-a<a:只有一種選擇,就是減去一個a。
若減去之後爲必勝,則自己必敗。
若減去之後爲必敗,則自己必勝。
2】.b-a>a:多種選擇,
假設x是使得b-x*a<a的整數,如果從b-(x-1)*a之後,也就達到了狀態1 。
2.1如果減去之後是必敗態:
則當前狀態是必勝態
----------
2.2如果減去之後是必勝態,此時可以減去a*x,這樣就達到了2.1所說的必勝態的下一個狀態,也就是必敗態
所以當前狀態是必勝態
---------
Eg:
(4,17)如果17-12=5也就是(4, 5)必敗,所以直接-12就能必勝
(4,19)如果19-12=7也就是(4,7),對方必勝,那麼直接減去16達到(4,7)對的下一個(4,3)必敗狀態給對手
也就扭轉了局面。達到必勝態
所以,從初始狀態開始,首先達到自由度的2狀態的一方獲勝。
注意這裏循環中每次的first狀態發生變化
因爲每種狀態都是互推的,這次的必勝,下次的必敗。
所以當遇到可以停止的時候break;
#include <cstdio>
void swap(int &x,int &y){
int t;
t=x,x=y,y=t;
}
int main(){
int a,b;
while(scanf("%d%d",&a,&b)!=EOF){
if(a==0&&b==0) break;
bool first=true;
while(true){
if(a>b) swap(a,b);
//第一種情況,b是a的倍數。必勝。
if( b%a ==0 ) break;
//第二種情況,必勝。
if( b-a > a ) break;
b-=a;
first=!first;
}
if(first) puts("Stan wins");
else puts("Ollie wins");
}
return 0;
}