所謂博弈,就是兩人輪流進行決策,並且兩人都使用最優策略來獲取勝利。通俗的說就是兩個人都想獲得勝利,兩個人都有頭腦,並且不會失誤。博弈的次數是有限的,兩人遵循的規則是相同的。
1.巴什博弈
有一堆石子,共有n塊,兩個人輪流取石子,每次至少取1塊,最多取m個,最後取光者獲勝(假設A,B兩個人,規定A先操作)。
(1)當n=(m+1)*k時,(k為任意正整數),當A先取石子時,A取X塊石子,無論X為多少,B只要取(m+1-x),則B必勝,此時為A的必敗態。
(2)當n=(m+1)*k+r(k,r為任意正整數,r不大於m),此時A先取r塊,那麼B始終處在(m+1)*k的狀態,由(1)可知,此時A一定贏,為A的必勝態。
通過以上就可以變形從而解決很多問題。。
例1:假設有一個箱子,可以裝n個物品,每次最多可以裝m個,最少可以裝1個,A,B輪流操作,最後裝滿箱子的人獲勝。
偽代碼如下:
if(n%(m+1))
A獲勝
else
B獲勝
例2:
假設一堆有n個物品,每次最多取m個,最少取1個,最後取光者輸(A先進行)
偽代碼:
if((n-1)%(m+1)==0)
B 獲勝
else
A獲勝
看完基本原理刷幾道水題吧,啊哈哈。。。
HDU1846 http://acm.hdu.edu.cn/showproblem.php?pid=1846
代碼如下:
1 #include<stdio.h> 2 #include<algorithm> 3 #include<iostream> 4 using namespace std; 5 int main() 6 { 7 int t,m,n; 8 cin>>t; 9 while(t--){ 10 cin>>n>>m; 11 if(n%(m+1)) 12 cout<<"first"<<endl; 13 else cout<<"second"<<endl; 14 } 15 } View Code
這個是最基本的啦,直接套模板。
再看一個題吧
HDU1847 http://acm.hdu.edu.cn/showproblem.php?pid=1847
這個題就是在巴什博弈的模板的基礎上小小的改動啦一下,思考一下就好啦。。
題目說每次取牌的數目只能是2的冪數,且每次Kiki先開始取牌,我們從特殊情況開始討論
1.當牌數n就是2的冪數的時候,Kiki直接拿走所有的牌,此時Kiki獲勝。
2.當牌數n不是恰好是2的冪數,這個時候如果把牌分成x個部分,每個部分都是由2的冪數組成,那麼如果x為奇數,就是Kiki贏,否則就是Cici贏。
思路理解啦,咱們來看代碼吧,這個思路是從學長那裡借鑒來的,哈哈!!!!!!!!!!
1 #include<stdio.h> 2 #include<iostream> 3 #include<string.h> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=1005; 7 bool used[maxn]; 8 void check() 9 { 10 int n; 11 memset(used,false,sizeof(used)); 12 for(int i=0;i<maxn;i++){ 13 if(!used[i]){ 14 int shu=1; 15 while(shu+i<maxn){ 16 used[shu+i]=true; 17 shu<<=1; 18 } 19 } 20 } 21 22 } 23 int main(){ 24 check(); 25 int m; 26 while(cin>>m){ 27 if(used[m]){ 28 cout<<"Kiki"<<endl; 29 30 } 31 else 32 33 cout<<"Cici"<<endl; 34 } 35 } View Code
針對這道題,還有另外一種想法。。
題目說的是2的冪次,那麼如果每次留給對手的都是3的倍數的話,對手如果取1,你就可以再取一點點,仍然留給對手3的倍數,如果對手取2的冪次,那麼你就直接取1啦嘛。。
代碼如下:
1 #include<stdio.h> 2 #include<iostream> 3 #include<algorithm> 4 #include<string.h> 5 using namespace std; 6 int main(){ 7 int n; 8 while(cin>>n){ 9 if(n%3==0) 10 cout<<"Cici"<<endl; 11 12 13 else cout<<"Kiki"<<endl; 14 } 15 } View Code