进阶实验2-3.1 海盗分赃 (25分)--递推

 

 解题思路:这道题一直都没想明白要如何求解,后在网上看到这篇大神的文章(见https://blog.csdn.net/fire_for_you/article/details/101981707受益良多,感谢博主分享) ,才知道这道题实际是一道递推题,即要先预测下一次的结果来判断此次分配方案,挺有意思的一道题。

先大概讲下自己的理解:(拿样例来说D=10,P=7)

如若当前是第7号海盗提出分配方案,由于此时船上仅有7号一个海盗,则意味着7号海盗获得全部钻石。

如若当前是第6号海盗提出分配方案,则表明之前5个海盗均已被丢下海,此时船上只剩下6号和7号,又考虑到提出的方案要获得大半数人的同意,此时是要2个人同意,则6号为了活命,只能将所有钻石全部给7号。

如若当前是5号海盗提出分配方案,则表明之前4个海盗均已被丢下海,此时船上只剩下5、6和7号,若5号想要自己得到的钻石最多,则需预测下一轮,即6号提出的方案,如此,可知5号要获得超过半数的支持票(即2个海盗,含5号自己,同意此方案),必须拉拢6号,则5号分配给6号1个钻石即可(因为如果是轮到6号提方案,意味前5个海盗均被丢下海,6号为了保命,一个钻石都得不到)。

如若当前是4号海盗提出分配方案,则表明之前3个海盗均已被被丢下海,此时船上只剩下4、5、6、7号海盗。若4号海盗想要自己得到的钻石最多,则需要预测下一轮,即5号海盗提出的方案,如此,可知,4号要获得超过半数的支持票(即3个海盗,含4号自己,同意此方案),必须拉拢6号和7号,因为根据5号提的方案,选出分配到钻石最少的2个海盗6号和7号(6号仅获得1个钻石,而7号1个钻石都得不到),并在5号提的方案基础上,在给6、7号多分配一个钻石,才能通过4号提出的方案,即4号需要分配6号2个钻石,和7号1个钻石。

如此类推...

方案分配见下表

#include <stdio.h>
#include <string.h>
#define Max 100+1
int main() {
    int d,p;
    scanf("%d %d",&d,&p);
    int ans[p+1];
    memset(ans,0,sizeof(ans));
    int pos=p-2;//倒数第3个海盗开始
    while(pos!=0) {
        ans[pos]=d;
        int cnt=(p-pos+1)/2;
        int max=0;
        int i;
        int flag[p+1];
        memset(flag,0,sizeof(flag));
        while(cnt!=0) {    
            for(i=pos+1; i<=p; i++) {//寻找下一轮分配到最少钻石的海盗,进行拉拢
                if(ans[i]==max&&!flag[i]) {
                    ans[i]++;
                    flag[i]=1;
                    cnt--;
                }
                if(!cnt)
                    break;
            }
            max++;
        }
        for(i=pos+1; i<=p; i++) {
            if(flag[i]) {
                ans[pos]-=ans[i];
            } else
                ans[i]=0;
        }
        pos--;
    }
    printf("%d",ans[1]);
    return 0;

}

 另解,还发现个更巧妙的解法(https://blog.csdn.net/TOBEALISTENNER/article/details/79896856?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task)

海盗的人数超过三个人的时候就会出现规律

(1)一个人 分配的结果:D

(2)两个人 分配的结果:0,D

(3)三个人 分配的结果:D-1,1,0

(4)四个人 分配的结果:D-3,0,2,1
(5)六个人 分配的结果:D-4,0,1,2,1,0
(6)七个人 分配的结果:D-4,0,1,2,0,0,1
(7)八个人 分配的结果:D-5,0,1,2,0,1,1,0
(8)九个人 分配的结果:D-5,0,1,2,0,1,0,0,1
(9)十个人 分配的结果:D-6,0,1,2,0,1,0,1,1,0

规律:每次只需要给上一次金币数为0的家伙一枚金币,再给其中一个上一次得到一枚金币的家伙两枚金币,第一个海盗选票就超过一大半了!

转化为数学规律 当人数超过三个人的时候 第一个海盗得到的金币为: D - (P / 2 + 1)

然后,代码如此简单!!!泪流满面

#include <stdio.h>
int main()
{
    int d,p;
    scanf("%d %d",&d,&p);
    if(p==3)
    printf("%d",d-1);
    else
    printf("%d",d-(p/2+1));
    return 0;
}
原文地址:https://www.cnblogs.com/snzhong/p/12588915.html