海盗与金币

Posted 8023spz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了海盗与金币相关的知识,希望对你有一定的参考价值。

12名海盗在一个小岛上发现了大量的金币,后统计一共有将近5万枚。
登上小岛是在夜里,天气又不好。由于各种原因,有的海盗偷拿了很多,有的拿了很少。
后来为了“均贫富”,头目提出一个很奇怪的方案:
每名海盗都把自己拿到的金币放在桌上。然后开始一个游戏。
金币最多的海盗要拿出自己的金币来补偿其他人。
补偿的额度为正好使被补偿人的金币数目翻番(即变为原来的2倍)。
游戏要一直进行下去,直到无法完成。
(当金币数最多的不只一个人或最多金币的人持有金币数不够补偿他人的)

游戏就这样紧张地进行了,一直进行了12轮,恰好每人都“放血”一次,
更离奇的是,刚好在第12轮后,每个人的金币数居然都相等了!! 这难道是天意吗?

请你计算,游戏开始前,所有海盗的初始金币数目,从小到大排列,中间有一个空格分开。

答案形如:
8 15 29 58 110 ...
当然,这个不是正确答案。

注意:
需要提交的是一行空格分开的整数,不要提交任何多余的内容。
分隔符要用一个西文的空格,不要用其它符号(比如逗号,中文符号等)

 

我的答案:

 

代码:

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>

using namespace std;
int have[12],ans[12],flag;
bool vis[12] = {true};
bool could(int k) {
    for(int i = 0;i < 12;i ++) {
        if(i != k) {
            if(have[i] % 2 == 0) {
                have[i] /= 2;
                have[k] += have[i];
            }
            else {
                for(int j = 0;j < i;j ++) {
                    if(j != k) {
                        have[k] -= have[j];
                        have[j] *= 2;
                    }
                }
                return false;
            }
        }
    }
    return true;
}
void recover(int k) {
    for(int i = 0;i < 12;i ++) {
        if(i != k) {
            have[k] -= have[i];
            have[i] *= 2;
        }
    }
}
void dist(int k) {
    for(int i = 0;i < 12;i ++) {
        if(i != k) {
            ans[k] -= ans[i];
            ans[i] *= 2;
        }
    }
}
void print() {
    for(int i = 0;i < 12;i ++) ans[i] = have[i];
    for(int i = 0;i <= 12;i ++) {
        int max_ = 0;
        cout<<""<<i<<"";
        for(int j = 0;j < 12;j ++) {
            cout<<" "<<ans[j];
            if(ans[max_] < ans[j]) max_ = j;
        }
        cout<<endl;
        if(i < 12) dist(max_);
    }
}
void dfs(int k) {
    if(flag) return;
    if(k >= 11) {
        print();
        flag = 1;
        return;
    }
    for(int i = 1;i < 12;i ++) {
        if(flag) return;
        if(!vis[i] && could(i)) {
            vis[i] = true;
            dfs(k + 1);
            vis[i] = false;
            recover(i);
        }
    }
}
int main() {
    int d = 50000 / ((1 << 11) * 12) * (1 << 11);
    have[0] = d / 2 * 13;
    for(int i = 1;i < 12;i ++) {
        have[i] = d / 2;
        vis[i] = false;
    }
    dfs(0);
}

 

以上是关于海盗与金币的主要内容,如果未能解决你的问题,请参考以下文章

海盗分金问题(博弈)

算法浅谈——递归算法与海盗分金问题

面试总结: 头脑风暴题目

算法笔记_206:第五届蓝桥杯软件类决赛真题(Java语言A组)

海盗分金问题SQL求解(贪心算法)

海盗分金