重提强盗分宝石问题

oyd 2003-04-16 07:06:51
问题:
有5个强盗A,B,C,D,E,得到100个金币,决定瓜分掉,分法怪异:
首先A提出分法,B,C,D,E表决,如果不过半数同意,就砍掉A的头(2:2也砍掉)
然后由B来分,C,D,E表决,如果不过半数同意,就砍掉B的头
依次类推,如果假设强盗都足够聪明,在不被砍掉头的同时获得最多的金币。

许多人的答案似乎都是
97,0,1,1,1
有代表性的理由如下:
每个强盗都很聪明,所以e虽然占有了有利位置,他也该想到c d为了活命一定支持b,既然c d 无论如何都要支持b,也不可能从b 手中拿到任何好处,所以a死了,cde都拿不到钱,为了拿最多的钱,只要a给一点点好处就会受到cde 的支持.所以最后最后结果一定是
a:97
b:0
c:1
d:1
e:1

可是你们忽略了一个问题:轮d分配时,他必死,所以他会同意c的任何方案,以避免c死后他也死的结果。这样c就可以提出100,0,0的方案来。
口说无凭,人的思维难免会有疏漏,用程序来作答吧。
程序运行的结果:5个强盗时最佳方案为97,0,1,0,2

/*程序:robber.cpp,vc++6.0下编译通过
* 因为100颗宝石用时间比较长,所以减为10颗
* vote函数用于模拟强盗投票,displaymethod函数用于显示方案
* 基于运算速度考虑,中间结果的输出被注释掉 。
*
*/


#include <iostream>
typedef struct _method
{
int stone[100];//存每个强盗分到的宝石数
int robbernum;//存强盗的数目
}Method;
Method *pBestMethod[100];//全局变量,用于存入已经找到的最佳方案
const int MAXSTONENUM=10;//待分配的宝石数
class Robber
{
public:
Robber(int num)
:m_num(num)
{
m_goodmethod.robbernum=0;
m_goodmethod.stone[num]=0;
}
bool vote(Method method);//对方案投票
int profit(Method method);
Method GetBestMethod();
void DisplayMethod();
private:
void Get(int m,int n);//用于列举所有方案的递归函数
void judge();//判断和比较方案的过程
const int m_num;//强盗的编号
Method m_method;//用于临时存储方案
Method m_goodmethod;//存储好方案
};


bool Robber::vote(Method method)
{
Method nextMethod;
do
{
Robber nextRobber(--method.robbernum);//下一个制定方案者
nextMethod=nextRobber.GetBestMethod();
}
while(nextMethod.stone[nextMethod.robbernum]==-1);
if(this->profit(method)>this->profit(nextMethod))
{
//std::cout<<"r"<<m_num<<":O ";//O表示同意
return true;
}
//std::cout<<"r"<<m_num<<":X ";//X表示否决
return false;
}
int Robber::profit(Method method)
{
return method.stone[m_num];
}
Method Robber::GetBestMethod()
{
Method method;
if(m_num==1)
{
method.stone[1]=MAXSTONENUM;
method.robbernum=m_num;
return method;
}
if(pBestMethod[m_num]!=NULL)return *pBestMethod[m_num];//已有方案
Get(MAXSTONENUM,m_num);
if(m_goodmethod.robbernum==0)//找不到可以通过投票的方案
{
std::cout<<"I am dead";
m_method.robbernum=m_num;
method=m_method;
method.stone[m_num]=-1;
}
else method=m_goodmethod;
pBestMethod[m_num]=new Method;
*pBestMethod[m_num]=method;
return method;

}
void Robber::Get(int m,int n)//把m个数分到n个人
{
if(m==0)
{
for(int i=1;i<=n;i++)
{
m_method.stone[i]=0;
}
m_method.robbernum=m_num;
judge();
return;
}

if(n==1)
{
m_method.stone[n]=m;
m_method.robbernum=m_num;
judge();
return;
}
for(int i=m;i>=0;i--)
{
m_method.stone[n]=i;
Get(m-i,n-1);
}


}
void Robber::judge()
{
int votes=1;
//DisplayMethod();
for(int i=m_num-1;i>=1;i--)
{
Robber robber(i);//假想其他强盗的投票
if(robber.vote(m_method))votes++;

}
if ((2*votes>m_num)&&(profit(m_method)>=profit(m_goodmethod)))
{//半数以上通过,且不比原先的方案差。
m_goodmethod=m_method;
}
}
void Robber::DisplayMethod()
{
std::cout<<std::endl;
for (int i=m_num;i>0;i--)
{
std::cout<<m_method.stone[i]<<" ";
}
std::cout<<"\t";
}
void main()
{
int num;
while(true)
{
std::cout<<"Input Robber number"<<std::endl;
std::cin>>num;

Robber theRobber(num);
Method method;
method=theRobber.GetBestMethod();
std::cout<<std::endl;
for(int i=method.robbernum;i>=1;i--)
std::cout<<method.stone[i]<<" ";
for(i=num-1;i>=1;i--)
{
Robber robber(i);
robber.vote(method);
}
}
}

...全文
47 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
ninesong 2003-04-22
  • 打赏
  • 举报
回复
提出解决方案参与投票的解决是98 。。。。。
提出解决方案不参与投票的解决是97,0,1,0,2
gumbour 2003-04-21
  • 打赏
  • 举报
回复
但还有一个前提是每个强盗都珍惜自己的生命
我记得是自己利益不受影响的时候,强盗认为死的人越多越好
如果前面的人死掉,自己的生命会受到影响,他会希望前面的人死掉吗?
DavidBone 2003-04-18
  • 打赏
  • 举报
回复
up
killerqueen1208 2003-04-16
  • 打赏
  • 举报
回复
首先,从进行到只有两名海盗时开始分析,几只剩下4和5号海盗,由于只有两人,故无论4怎样分,4都比死,5得100枚钻石。
现在加上3号海盗,由于在上一种情况中,5能得到所有钻石,故5希望3死,只剩下4和5,故3无论怎样分5都不会同意,5必投反对票,而4不希望自己死,故给4号海盗0枚钻石就会同意,而3号海盗本身比同意自己的分法,故分法为:100,0,0。这样可以得到4的同意票和5的反对票。
现在再加上2号海盗,同上,2号海盗无论怎样分3号都不会同意,故2要得到4和5的两枚赞同票他才能不死,又因为海盗认为获得的钻石不变,死的人越多越好,故应给4号和5号各一枚钻石,故分法为:98,0,1,1。
再加上1号海盗,2号必不会同意,故他要在3,4,5号海盗中得到2票,这样的话,它要分给3号海盗一枚,得到一票,而可以分给4和5两人中一人0枚,另一人2枚得到另一票,故分法为:97,0,1,0,2或97,0,1,2,0

我这样分的原因是我找到的原题还有一个条件为:在分到钻石同样多的情况下,强盗认为斯的人越多越好!

33,010

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧