日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

递归用法之“海盗分赃难题”

發(fā)布時(shí)間:2024/4/17 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 递归用法之“海盗分赃难题” 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

海盜分贓難題:

  十個(gè)海盜要瓜分100枚金幣,為此他們擬定了以下規(guī)則。

  從船長到廚子每個(gè)海盜由高到低共分十個(gè)等級(jí),分配權(quán)在最高等級(jí)的海盜手里。他可以任意分配每個(gè)海盜的所得,但必須取得一半或一半以上海盜(包括自己在內(nèi))的支持,否則他將被同伴處死。處死之后分配權(quán)將轉(zhuǎn)移到下一個(gè)等級(jí)最高的海盜手里,當(dāng)然,他也將面臨同樣艱難的選擇。

  基于海盜們貪婪而兇殘的本性,每個(gè)沒有分配權(quán)的海盜都想分得更多的金幣和處死自己的上級(jí)。但相對后者而言,多分得一枚金幣也許更有吸引力。我們假定所有的海盜都是深思熟慮的老手,他們能精確地計(jì)算自己未來的得失,從而根據(jù)利益最大原則支持或反對上級(jí)的分配。

  問:作為一號(hào)海盜的船長有什么辦法為自己分得最多的金幣而不被處決?


問題的背景:

  “海盜分贓”算是一道比較經(jīng)典的智力測試題,也是我所見過的最有挑戰(zhàn)性的一道。據(jù)說你能在半小時(shí)內(nèi)解開說明你很了不起,至少不會(huì)輸給那些“深思熟慮的老手”。對啦,我的意思是說所有的海盜必須是知道答案的,否則本題的假設(shè)不能成立,我最欣賞這一點(diǎn)。


解題的關(guān)鍵:

  解題的關(guān)鍵在于反向推理。

  假設(shè)只剩下九號(hào)和十號(hào)海盜,按規(guī)則應(yīng)該由九號(hào)海盜分配。猜會(huì)怎么著?九號(hào)一定會(huì)把100枚金幣統(tǒng)統(tǒng)據(jù)為己有,因?yàn)檫@時(shí)已經(jīng)沒有任何力量可以阻止他這么做了,他給自己投一票就能達(dá)到50%的支持率。

  由此,“深思熟慮”的十號(hào)海盜一定會(huì)明白處死八號(hào)自己最好的結(jié)果也將是一無所得。

  現(xiàn)在假定由八號(hào)來分贓,十號(hào)一定會(huì)這么想:“他至少應(yīng)該分給我一枚金枚,否則我一定投票弄死他。”

  “深思熟慮”的八號(hào)也一定不難猜到十號(hào)的心理動(dòng)向,因?yàn)楦鶕?jù)推理,十號(hào)的打算是必然的結(jié)果。于是他決定用最小的代價(jià)——1枚金幣——去賄賂十號(hào)海盜。如此,加上他自己的支持,2比1,他肯定死不了!所以九號(hào)海盜一毛錢也別想撈。

  按照上面的思路可以一直逆推回一號(hào)海盜,船長可以根據(jù)船員們的心理作出對自己最有利的分配方案。


遞歸的作用:

  如果要求我們用程序來模擬這一過程該怎么辦?

  遞歸。對!大多數(shù)訓(xùn)練有素的程序員一定會(huì)先想到遞歸。因?yàn)樗鼘?shí)在就是遞歸類問題的典范。

  按照我們的分析過程,我把偽代碼寫在下面:

/**DivideSpoils為遞歸函數(shù)*參數(shù)num為參與分贓的海盜數(shù)*分贓成功函數(shù)則返回分贓結(jié)果,否則函數(shù)返回空值*/ DivideSpoils (num)if num=2 thenrst[0]=100rst[1]=0return rstendifrst=DivideSpoils(num-1)if rst=空值 thenreturn 空值else/*重新分配,使至少一半的海盜感到滿意*/rst=Redivide(rst,num-1)return rstendifend/**Redivide負(fù)責(zé)對金幣重新分配,使至少一半的海盜感到滿意*oldrst為num個(gè)海盜的分配結(jié)果*分配成功則返回num+1個(gè)海盜的分配結(jié)果,否則函數(shù)返回空值*/ Redivide (oldrst,num)rst := 1X(num+1)維數(shù)組s := 1Xnum維數(shù)組half=[num/2] //[x]為不大于num/2的最大整數(shù)/*對oldrst從小到大排列,只需排出前第half位,排列后的下標(biāo)存入s中*/s[i]={k, oldrst[s[k-1]]<=oldrst[k]} when i<halfs[i]=i when i>=half/*賄賂一半的海盜,使他們能多分一枚金幣*/rst[s[i]+1]=oldrst[s[i]]+1 when i<half/*余下的另一半一分錢不給*/rst[s[i]+1]=0 when i>=half/*余下金幣則歸自己*/rst[0]=余下金幣if rst[0]<0 then //rst[0]<0說明沒有足夠金幣賄賂部下,分配失敗return 空值elsereturn rstendifend

  

由以上代碼來看,遞歸的停止條件來自我們上面基于兩個(gè)海盜分贓結(jié)果的假設(shè)。我們似乎可以進(jìn)一步簡化它:

if num=1 thenrst[0]=100return rst endif

這樣做程序也能工作,并得到了正確答案。可想見遞歸是門很靈活的藝術(shù)。


問題的擴(kuò)展:

  分贓問題很簡單是不是?不簡單!還記得三個(gè)海盜分贓時(shí)我們準(zhǔn)確分析了十號(hào)的心理么?是不是還遺漏什么了?是,九號(hào)怎么想的我們完全沒有去考慮,這種粗暴的態(tài)度可能會(huì)給分配者帶來無法預(yù)料的災(zāi)難!

  怎么說?我們不妨設(shè)想當(dāng)九號(hào)推斷出自己將受到不公正待遇的時(shí)候,他可能會(huì)私下跟十號(hào)協(xié)商。他可能信誓旦旦地保證:“嘿,兄弟,我們把八號(hào)給做了,剩下的金幣四六分怎么樣?” 盡管他在履行承諾后的所得要低于自己的部下,但這比起空手而歸卻要好得很多,況且他們還結(jié)果了一個(gè)上級(jí)。

  八號(hào)在得知這種情況后一定很恐慌,因?yàn)樗呀?jīng)完全不能決定自己的命運(yùn)了。他必須盡最大可能去賄賂十號(hào),60金幣?70?100?!!!他驚恐地睜大了眼睛,他怎么會(huì)知道九號(hào)承諾了多少,也許是100金幣?九號(hào)認(rèn)定要取自己性命了?!

  我們可以想像這時(shí)十號(hào)肯定頗為滿意,他似乎惟一要做的就是不動(dòng)聲色,看誰出的價(jià)位更能打動(dòng)他。其實(shí)不然,因?yàn)榘颂?hào)可能會(huì)轉(zhuǎn)而與九號(hào)密談,比如說之前九號(hào)承諾干掉八號(hào)以后自己只拿40金,現(xiàn)在八號(hào)承諾給九號(hào)41金,九號(hào)就會(huì)反過到擁護(hù)8號(hào)...

  到此為止海盜分贓問題就已經(jīng)不再是單純的智力測試了,而應(yīng)該配得上另一個(gè)更體面的名字:博弈論。

  最后海盜們會(huì)不會(huì)達(dá)成某個(gè)滿意的協(xié)議,我現(xiàn)在還不知道,這個(gè)問題打發(fā)給以后的空閑時(shí)間。


c語言源代碼:

View Code #include<stdio.h>
#include
<stdlib.h>

const int COINS=100;
const int PIRATES=10;

int* divi_spoils(int);
int* redivide(int*,int);
int* rank(int*,int,int);

int main(void){
int i;
int* rst;

rst
=divi_spoils(PIRATES);
if(rst){
for(i=0;i<PIRATES;i++)
printf(
"Pirate<%d>: %d coins\n",i+1,rst[i]);
}
else{
printf(
"Be Executed!\n");
}

free(rst);
return 0;
}

int* divi_spoils(int total){
int* rst=NULL;

if(total==1){
rst
=(int*)malloc(total*sizeof(int));
rst[
0]=COINS;
return rst;
}

rst
=divi_spoils(total-1);
if(rst==NULL)
return NULL;
else{
rst
=redivide(rst,total-1);
return rst;
}
}

int* redivide(int* old_rst, int n){
int i,left=COINS,half=n/2;
int* s,* rst;

s
=rank(old_rst,n,half);
rst
=(int*)malloc((n+1)*sizeof(int));
for(i=0;i<half;i++){
rst[s[i]
+1]=old_rst[s[i]]+1;
left
-=rst[s[i]+1];
}
for(i=half;i<n;i++)
rst[s[i]
+1]=0;
free(s);
free(old_rst);

if(left<0){
free(rst);
return NULL;
}
else{
rst[
0]=left;
return rst;
}
}

int* rank(int* data, int n, int len){
int i,j,tmp;
int* s;

s
=(int*)malloc(n*sizeof(int));
for(i=0;i<n;i++)
s[i]
=i;

for(i=0;i<len;i++)
for(j=n-1;j>i;j--)
if(data[s[j]]<data[s[j-1]]){
tmp
=s[j];
s[j]
=s[j-1];
s[j
-1]=tmp;
}

return s;
}


  

轉(zhuǎn)載于:https://www.cnblogs.com/keenlog/archive/2011/09/03/2165757.html

與50位技術(shù)專家面對面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖

總結(jié)

以上是生活随笔為你收集整理的递归用法之“海盗分赃难题”的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。