P个海盗偷了D颗钻石后来到公海分赃,一致同意如下分赃策略:
首先,P个海盗通过抽签决定1-P的序号。然后由第1号海盗提出一个分配方案(方案应给出每个海盗分得的具体数量),如果能够得到包括1号在内的绝对多数(即大于半数)同意,则按照该分配方案执行,否则1号将被投入大海喂鲨鱼;而后依次类似地由第2号、第3号等等海盗提出方案,直到能够获得绝对多数同意的方案出现为止,或者只剩下最后一位海盗,其独占所有钻石。请编写一个程序,给出第1号海盗的钻石分配方案中自己分得的钻石数量。
附带的三个假定:
1) “聪明”与“贪婪”假定:每个海盗总能够以本人利益最大化作为行为准则;
2) “人性化”假定:在能够取得尽量多钻石的情况下,海盗不会故意致同伙于死地;
3) “无偏见”假定:海盗之间没有个人恩怨,分给其他海盗钻石的次序以小序号优先为原则。
输入格式说明:
输入2个正整数D和P(3<=P<=D<=100)。
输出格式说明:
输出第1号海盗的钻石分配方案中自己分得的钻石数量。
样例输入与输出:
序号 | 输入 | 输出 |
1 | 10 7 | 6 |
2 | 3 3 | 2 |
3 | 100 3 | 99 |
4 | 100 100 | 49 |
逆向思考,每个海盗只需争取幸存者中超过半数的票。以20个宝石,5个海盗为例。
假如只剩4号5号两个海盗,提方案的4号海盗只能提出给自己0个钻石,否则肯定被5号海盗拒绝,即方案为4、5号:0,20。
则剩下3个海盗的时候,提方案的3号海盗只需给4号海盗1个钻石就能争取到他的一票,即方案为3、4、5号:19,1,0。
同理根据上一步,剩下4个海盗的时候,提方案的2号海盗只需争取到上一步最惨的4号5号的票就能过半,即方案为2、3、4、5号:17,0,2,1。
于是5个海盗都在的时候,提方案的1号海盗只需提出17,0,1,0,2,争取到上一步最惨的3号和5号两个海盗的票即可。
由于最终只需输出1号给自己分的钻石数,我们可以对上一轮的人按钻石数从小到大进行排序,给最惨的一半人加1个钻石。
而如果要求输出从1号提出的具体方案。则需要用结构体(包含海盗编号和钻石数两个变量)。在最后按海盗编号进行排序,输出钻石即可。
/*2015.8.5cyq*/
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
int D,P;
cin>>D>>P;
vector<int> a(P+1);//a[i]倒数第i个海盗,a[P]为最先提方案的1号海盗
//若只剩3个人,提方案的海盗只需分给倒数第二个海盗1个钻石就能争取到票
a[1]=0;
a[2]=1;
a[3]=D-1;
for(int i=4;i<=P;i++){
sort(a.begin()+1,a.begin()+i);
int used=0;
int j;
for(j=1;j<=i/2;j++){//给半数钻石最少的海盗多分1个
++a[j];
used+=a[j];
}
for( ;j<i;j++)//剩下的海盗都给0个钻石
a[j]=0;
a[i]=D-used;
}
cout<<a[P]<<endl;
return 0;
}