• 进阶实验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;
    }
  • 相关阅读:
    java笔试面试题目收集(一)
    java--用 * 打印出各种图形(新手请进)
    TextView属性大赏
    Meterial Or Ios ?
    android开发之后端云bmob的使用
    关于android开发自定义view
    第二周作业——面向过程(或者叫结构化)分析方法与面向对象分析方法到底区别在哪里?
    移动APP开发使用什么样的原型设计工具比较合适?
    测试
    转:nohup命令及其输出文件
  • 原文地址:https://www.cnblogs.com/snzhong/p/12588915.html
Copyright © 2020-2023  润新知