重提强盗分宝石问题
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);
}
}
}