博弈學習(三) HDU 1538 A Puzzle for Pirates(經典的海盜分金推理)
轉載請註明出處,謝謝 http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
題目:這是一個經典問題,有n個海盜,分m塊金子,其中他們會按一定的順序提出自己的分配方案,如果50%以上的人贊成,則方案通過,開始分金子,如果不通過,則把提出方案的扔到海里,下一個人繼續。
http://acm.hdu.edu.cn/showproblem.php?pid=1538
首先我們講一下海盜分金決策的三個標準:保命,拿更多的金子,殺人,優先順序是遞減的。
同時分為兩個狀態穩定狀態和不穩定狀態:如果當n和m的組合使得最先決策的人(編號為n)不會被丟下海, 即遊戲會立即結束, 就稱這個狀態時"穩定的". 反之, 問題會退化為n-1和m的組合, 直到達到一個穩定狀態, 所以乘這種狀態為"不穩定的".
接下來我們從簡單的開始分析:
如果只有兩個人的話:那麼2號開始提出方案,這時候知道不管提什麼,他自己肯定贊成,過半數,方案通過,那麼2號肯定把所有的金子都給了自己。
如果只有三個人的話:那麼3號知道,如果自己死了,那麼2號肯定能把所有金子拿下,對於1號來說沒有半點好處。
那麼他就拿出金子賄賂1號,1號拿到1個金子,總比沒有好,肯定贊成3號,剩下的3號拿下。
如果只有四個人的話:那麼4號知道,如果自己死了,那麼1號拿到1個金子,2號什麼都沒有,3號拿下剩下的金子。
那他就可以拿出部分金子賄賂2號,2號知道如果4號死了,自己將什麼都沒有,他肯定贊成4號。
如此類推下去,貌似就是第一個決策的時候,與他奇偶性相同的人會被賄賂拿到1個金子,剩下的全歸提出方案的人所有。
但是會有一個問題便是,如果金子不夠賄賂怎麼辦。
情況1、我們首先歸納之前的,如果n<=2*m時候,前面與n相同奇偶性的得到1個金子,剩下的第n個人拿下。
情況2、如果n==2*m+1,第n個人拿出m個金子賄賂前面的m個人。自己不拿金子,這樣剛好保證自己不死,這就是之前提到的優先順序,首先得保命,如果自己拿了一個金子,那麼前面就有一個人會反對,因為對於那個人,不管怎麼樣都分不到金子,則輪到第三個原則,殺人,肯定投反對票。
剩下來我們考慮,錢不夠賄賂的情況:
我們將問題具體化:如果有500個海盜,只有100個金子,那麼前面201個已經分析過了。
對於202號來說,自己不能拿金幣,而賄賂上一輪沒有拿到金幣的101人中的100人就夠了。
對於203號來說,需要102個人的支援,顯然加上他自己,還需要101票,而金子不夠賄賂,別人會反對,而達到殺人的目的。
對於204號來說,他知道一旦自己死了,203號是必死,抓住這點,203必然支援他,因為203號寧可不要金幣,也要保住性命,所以204號把100個金幣分給之前的100個人,然後203和他自己的兩票保證自己不死。
對於205號來說,203,和204是不會支援他的,因為一旦205死了,他們不僅可以保住性命,而且還可以看著205死掉。所以205是必死
那麼206呢,雖然205必死,會支援他,但是還是缺一票,所以必死。
對於207呢,205和206之前是必死,會支援他,但是加上自己以及100個賄賂名額,還是必死
對於208號,205,206.,207因為後面是必死的,肯定會支援208成功,那麼208剛好能湊齊104票,得以保命。
以下我們猜想:n=2*m+2^k的情況下,是可以保命的,稱為穩定狀態,否則為不穩定狀態,我們證明一下:
首先對於n來說,有m票賄賂,但是對於2*m+2^(k-1)以前必死的死,他們會支援2*m+2^(k-1),因為他們肯定拿不到錢,而且支援2*m+2^(k-1),另外根據殺人原則,希望之後的人都死,輪到2*m+2^(k-1)決策的時候保命就行了。
同理2*m+2^(k-1)到2*m+2^k之間的2^(k-1)-1個人來說,他們必死,所以必定支援2*m+2^k,加上m個金幣賄賂的,加上他自己,剛好有m+2^(k-1)。這樣剛好湊齊一半,可以不死。
證明完畢:2*m+2^k的人可以保命,否則必死。
我們考慮一下分金幣情況:
情況3:對於第2*m+2^k個人來說,他可以保命,肯定分不到金子,而他手上的m個金子,可以賄賂m個人,但是具體是哪些人是不定的。則不管是不能分到金子,還是可能分不到金子的人來說,結果都為0。
情況4:對於2*m+2^(k-1)到2*m+2^k之間的來說,他們的決策是必死,而在他們決策的時候,其它人分得金幣情況也為0。
我們來解釋一下金幣的不確定性:
金幣數量的不確定性:由上面的推理可知, 當n=2m+2時, 上一輪推理沒有分到金幣的人的金幣數量首次具有不確定性, 並且在n>2m+2時, 這種不確定性一定會延續下去, 輪到因為n號決策者之前的一個人決策時, 那個人肯定分不到金幣了, 所以在上一輪推理中沒有分到金幣的人的個數一定大於m.
綜合情況1,2,3,4便是本題的解,
程式碼如下:
- #include<iostream>
- #include<cstdio>
- #include<ctime>
- #include<cstring>
- #include<cmath>
- #include<algorithm>
- #include<cstdlib>
- #include<vector>
- #define C 240
- #define TIME 10
- #define inf 1<<25
- #define LL long long
- using namespace std;
- //儲存2的冪
- int fac[15]={2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
- void slove(int n,int m,int p){
- //金幣夠賄賂的情況
- if(n<=2*m){
- //不是決策者,而且奇偶性相同,都能被賄賂
- if(n!=p&&(n%2==p%2))
- printf("1\n");
- //剩下的都是決策者擁有
- else if(n==p)
- printf("%d\n",m-(n-1)/2);
- else
- //其餘人分不到金幣,他們的決策不影響全域性
- printf("0\n");
- return ;
- }
- //這時候的不同在於決策者不能拿金幣
- else if(n==2*m+1){
- if(p<2*m&&p&1)
- printf("1\n");
- else
- printf("0\n");
- return ;
- }
- int t=n-2*m,i;
- //這是剛好保命的情況,對於決策者來說,肯定沒有金幣
- //對於其它人來說,要麼肯定沒有金幣,要麼可能沒有金幣,不確定性
- for( i=0;i<14;i++){
- if(t==fac[i]){
- printf("0\n");
- return;
- }
- }
- for( i=1;i<14;i++)
- if(t<fac[i]){
- //決策者必死
- if(p>2*m+fac[i-1]&&p<2*m+fac[i])
- printf("Thrown\n");
- else
- printf("0\n");
- return ;
- }
- }
- int main(){
- int t,n,m,p;
- scanf("%d",&t);
- while(t--){
- scanf("%d%d%d",&n,&m,&p);
- slove(n,m,p);
- }
- return 0;
- }
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<vector>
#define C 240
#define TIME 10
#define inf 1<<25
#define LL long long
using namespace std;
//儲存2的冪
int fac[15]={2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
void slove(int n,int m,int p){
//金幣夠賄賂的情況
if(n<=2*m){
//不是決策者,而且奇偶性相同,都能被賄賂
if(n!=p&&(n%2==p%2))
printf("1\n");
//剩下的都是決策者擁有
else if(n==p)
printf("%d\n",m-(n-1)/2);
else
//其餘人分不到金幣,他們的決策不影響全域性
printf("0\n");
return ;
}
//這時候的不同在於決策者不能拿金幣
else if(n==2*m+1){
if(p<2*m&&p&1)
printf("1\n");
else
printf("0\n");
return ;
}
int t=n-2*m,i;
//這是剛好保命的情況,對於決策者來說,肯定沒有金幣
//對於其它人來說,要麼肯定沒有金幣,要麼可能沒有金幣,不確定性
for( i=0;i<14;i++){
if(t==fac[i]){
printf("0\n");
return;
}
}
for( i=1;i<14;i++)
if(t<fac[i]){
//決策者必死
if(p>2*m+fac[i-1]&&p<2*m+fac[i])
printf("Thrown\n");
else
printf("0\n");
return ;
}
}
int main(){
int t,n,m,p;
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&n,&m,&p);
slove(n,m,p);
}
return 0;
}
相關文章
- [經典演算法]海盜分金問題sql求解(貪心演算法)演算法SQL
- 人工智慧研究:經典推理和非經典推理人工智慧
- PostgreSQL技術週刊第2期:用PostgreSQL解海盜分金問題SQL
- 建立海盜的天堂:盜賊之海的AI(一)AI
- 博弈論經典模型解析(入門級)模型
- css經典佈局學習CSS
- 建立海盜的天堂:盜賊之海的AI設定(三):巨齒鯊、海怪和骷髏船的AI執行AI
- 博弈學習 (二) 斐波那契博弈
- oracle約束學習經典案例Oracle
- 字串函式庫的經典使用學習字串函式
- HDU5411CRB and Puzzle(矩陣快速冪)矩陣
- oracle臨時表的經典學習資料Oracle
- 一個設計模式的經典學習case!!!設計模式
- 大資料經典學習路線大資料
- 來自一篇推理小說的博弈問題
- Deep Crossing模型——經典的深度學習架構ROS模型深度學習架構
- 【博弈論】HDU - 7216 Triangle GameGAM
- 網路表述學習經典論文——DeepWalk
- 大資料經典學習路線,必看!!大資料
- 建立海盜的天堂:盜賊之海的AI設定(二):骷髏和鯊魚AI的祕密AI
- 機器是如何學習推理的?
- 下一代跨境電商平臺?Caribbean Pirates,這個區塊鏈海盜即將引領國際貿易革命Bean區塊鏈
- 幾道經典邏輯推理題,提高你的邏輯思考能力
- 我的Java開發學習之旅------>Java經典面試題Java面試題
- PHP 經典趣味演算法 (學習函式)PHP演算法函式
- PL/SQL經典學習筆記(6-10)SQL筆記
- PL/SQL經典學習筆記(2-5)SQL筆記
- 深度學習經典卷積神經網路之AlexNet深度學習卷積神經網路
- 深度學習與圖神經網路學習分享:CNN 經典網路之-ResNet深度學習神經網路CNN
- 博弈學習(一) NIM + SG函式函式
- SQL經典練習題48道之三(20-25)SQL
- PHP 三大經典模式初探PHP模式
- 【機器學習】深度學習與經典機器學習的優劣勢一覽機器學習深度學習
- 海盜灣的出售和Usenet的敗訴SENet
- Two Pirates - 2
- 海盜分贓演算法題演算法
- HDU 3600 Simple Puzzle 歸併排序 N*N數碼問題排序
- 學習外掛 -------- 成長過程(經典推薦)