[谜题]海盗分金-逆向思维

安妮女王复仇号上有n个海盗,一天他们洗劫了皇家港抢到了m枚金币,现在海盗们准备瓜分金币,但是分金币必须要遵循《海盗法典》。

法典规定:

金币不能分割;
船上的海盗需要按照地位进行排序,地位越高的海盗编号越高;
从编号最高的海盗开始提出金币分配方案,船上的海盗(包括提出方案的那个)一起对方案进行表决,如果分配方案得到一半或以上的海盗支持,那么方案就获得通过,如果方案没能得到半数支持,那么提出该方案的海盗就将被逼迫跳海去喂鱼,而后由编号第二大的海盗提出方案重复这一过程,直到某个海盗的方案获得通过。

假设:

每个加勒比海盗首先想到的是确保自己的性命(人之常情)
其次是获得更多的金币(海盗都是贪婪的)
他们希望看到更多的其他海盗跳海(估计每个海盗都想独占安妮女王复仇号)
所有的海盗都严格遵循这个优先级顺序,并且他们都是完全理性的,他们也知道其他海盗是完全理性的

先解决10个海盗分100枚金币的问题,下面用自己的语言分析:

题目:10名海盗抢得了窖藏的100块金子,并打算瓜分这些战利品。

这是一些讲民主的海盗(当然是他们自己特有的民主),他们的习惯是按下面的方式进行分配:
最厉害的一名海盗提出分配方案,然后所有的海盗(包括提出方案者本人)就此方案进行表决。如果50%或更多的海盗赞同此方案,此方案就获得通过并据此分配战利品。否则提出方案的海盗将被扔到海里,然后下面一个提名最厉害的海盗又重复上述过程。

介绍一下背景知识:

①假设所有海盗的地位是不一样的,可以按照凶狠程度排好序;
②而且每一个海盗都是很有逻辑的,非常理性,会很认真分析自己的利益;
③作为一个合格的海盗,他们是十分凶狠的,总是希望其他人都死掉才好;
④同时呢,自己的生命是摆在第一位的,金钱其次;
⑤还有一点,他们很现实,二鸟在林,不如一鸟在手。

问题:最凶的一名海盗应当提出什么样的分配方案才能使他获得最多的金子呢?

分析:

这是一个典型的动态规划问题,需要自底向上求解,简单来说,先分析最简单的情况,再推复杂的,也就是由基本问题开始。(就我来看,也可以叫做是逆向思维,毕竟投票进行到最后,只剩下几个人的时候是很简单的)

解答:

①首先,将所有海盗排好序,最厉害的海盗记作P10,最菜的海盗记作P1,接着从只有一个海盗开始分析:
至少需要 0 票
毫无疑问,一个人独吞。

P1
100

②加上P2:
至少需要 1 票
P2 随便提出一个方案,自己同意就好,这一票就达到总人数的一半了,所以干脆拿走100金子。

P2P1
1000

③下面就开始要好好考虑了:
至少需要 2票
P2想,只要干掉P3,那么所有金子一定是自己的,所以一定不会同意P3的方案。对于聪明的P3,知道P2是不会同意自己的,所以就想着怎么去收买(这个用词很恰当)P1,因为只有这样才能凑够2票(一定不能忘记自己的一票),大于总人数的一半(1.5)。
所以呢,P2一分不给(反正给多少都不领情),P1给1块,总比方案制定权落到P2手里的0要好些,最后算一算,自己还剩99,不错不错。

P3P2P1
9901

至少需要 2 票
那好,P4只需要收买一个人就好,谁呢。照着②的思路,P3是大概率不领情的,就从P2和P1里面选一个,当时买P2比较好。如果P2不支持P4,结果P4挂掉的话,自己就什么都没有了(轮到P3那块就投票成功了,③中的情况成立,轮不到②,可以说卡在③那里了),所以会支持P4,只要给一点好处,不然的话,也是很情愿看着他死翘翘的。P1和P2类似,但是收买他比较贵,因为③中他可是得到了1,而P2没有。
综上,P4花掉1块收买P2,完美,自己拿走99。

P4P3P2P1
99010

好了,到这里就看出规律来了,轮到海盗Pi,就看看轮到P(i+1)的情况,想办法收买这个时候得到金子少的人,没有得到的最后。
下面列出所有情况:
最右侧一栏表示轮到谁来制定方案

P10P9P8P7P6P5P4P3P2P1
100P1
1000P2
9901P3
99010P4
980101P5
9801010P6
97010101P7
970101010P8
9601010101P9
96010101010P10

P10会得到96块金子

接下来,把问题难度加大,

题目:500名海盗分100块金子

这就设计到金子不够的问题了,那么从什么时候开始短缺呢?
至少需要100票
从上面的规律来看,轮到P200时,编号为偶数的有1块金子,其他人没有。

P200P199P2P1
1010

至少需要101票
然后考虑P201,显然为了收买100人,自己没有了。

P201P200P199P2P1
00101

假设每次 P1~P200 中有100人被收买,其实每次只要收买上一种情况下没有得到好处的人即可,有很多种分配方案,这里做简化

至少需要101票
到了P202,最多收买100,自己还是没有,但可以保住性命。

P202P201P200P199P2P1
001010

至少需要102票
之后呢,对P203来说就麻烦了,需要得到102张票,除去100块金子收买的100人和自己,还需要一票,可是这个时候是不会得到的,因为P201和P202并没有得到好处(假设收买的人在P1~P200中),非常高兴看着他跳进海里喂鱼。那么P202就一定挂掉了。

至少需要102票
换成P204,他知道P203一定会死翘翘,所以断定他一定会支持自己,这样就得到了一个铁杆粉丝,就好办了,再花100块金子收买100人即可

至少需要103票
P205,他是没有铁杆粉丝的,因为P204不会一定去喂鱼,所以得不到这么多票,好的,乖乖跳海喂鱼。

接下来P206、P207也挂了,就好像傀儡一样,一定会喂鱼的海盗肯定支持前面的海盗,这种情况持续到有一个海盗会活下来为止,因为这个是大家都没事了,不愿意去管更前面的事,这样的话傀儡清零。
该P208了,惊喜的发现自己的傀儡攒够了,于是投票成功。
在这里插入图片描述
好的,这样一直算到P216,他是下一位幸运儿。
简单整理一下这里的存活者:P216、P208、P204、P202、P201、P200 … P1
有点规律:
偶数号的海盗收买前200人中偶数号的人,奇数号的海盗收买前200人中基数号的人。
那么对于500人分100块金子这个问题来说,前面44位大哥都跳海喂鱼去了,P456活下来,他收买了P1~P200中偶数号的人,分配结束。

那么,从另外一个方向分析题目

题目:将投票人数从至少50%改为超过50%

P10P9P8P7P6P5P4P3P2P1海盗最少票数
100P11
X100P22
10000P32
98011P43
970120P53

这里开始有不同了,P5只需要收买P2和P1其中一个即可。

P10P9P8P7P6P5P4P3P2P1海盗最少票数
9701011P64

这里需要强调,对P2、P1来说,上面一种分配方式中两人中有且仅有一人得到2块金币,是不确定的,这个时候P6给他们每人1块,二鸟在林,不如一鸟在手,他们很现实,所以会偏向肯定能拿到手里的1块,避免什么也得不到的可能发生,这样两人都被收买了。

P10P9P8P7P6P5P4P3P2P1海盗最少票数
96012100P74
960101011P85
9501210100P95
95010101011P106

所以P10可以拿到95块,分配结束。

  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
三壶谜题是一个经典的逻辑问题,通过使用三个容量不同的水壶,来实现特定容量的水的测量。以下是C++编程实现三壶谜题的一种可能解决方案: ```cpp #include <iostream> #include <queue> #include <set> using namespace std; struct State { int x, y, z; string path; }; void solveThreeJugs(int a, int b, int c, int d) { queue<State> q; set<pair<int, int>> visited; State init = {0, 0, c, ""}; q.push(init); visited.insert(make_pair(0, c)); while (!q.empty()) { State curr = q.front(); q.pop(); if (curr.x == d || curr.y == d || curr.z == d) { cout << curr.path << endl; return; } // 从x壶向y壶倒水 if (curr.x > 0) { int pour = min(curr.x, b - curr.y); State next = {curr.x - pour, curr.y + pour, curr.z, curr.path + "X" + to_string(pour) + "Y"}; if (visited.find(make_pair(next.x, next.y)) == visited.end()) { q.push(next); visited.insert(make_pair(next.x, next.y)); } } // 从x壶向z壶倒水 if (curr.x > 0) { int pour = min(curr.x, c - curr.z); State next = {curr.x - pour, curr.y, curr.z + pour, curr.path + "X" + to_string(pour) + "Z"}; if (visited.find(make_pair(next.x, next.z)) == visited.end()) { q.push(next); visited.insert(make_pair(next.x, next.z)); } } // 从y壶向x壶倒水 if (curr.y > 0) { int pour = min(curr.y, a - curr.x); State next = {curr.x + pour, curr.y - pour, curr.z, curr.path + "Y" + to_string(pour) + "X"}; if (visited.find(make_pair(next.x, next.y)) == visited.end()) { q.push(next); visited.insert(make_pair(next.x, next.y)); } } // 从y壶向z壶倒水 if (curr.y > 0) { int pour = min(curr.y, c - curr.z); State next = {curr.x, curr.y - pour, curr.z + pour, curr.path + "Y" + to_string(pour) + "Z"}; if (visited.find(make_pair(next.y, next.z)) == visited.end()) { q.push(next); visited.insert(make_pair(next.y, next.z)); } } // 从z壶向x壶倒水 if (curr.z > 0) { int pour = min(curr.z, a - curr.x); State next = {curr.x + pour, curr.y, curr.z - pour, curr.path + "Z" + to_string(pour) + "X"}; if (visited.find(make_pair(next.x, next.z)) == visited.end()) { q.push(next); visited.insert(make_pair(next.x, next.z)); } } // 从z壶向y壶倒水 if (curr.z > 0) { int pour = min(curr.z, b - curr.y); State next = {curr.x, curr.y + pour, curr.z - pour, curr.path + "Z" + to_string(pour) + "Y"}; if (visited.find(make_pair(next.y, next.z)) == visited.end()) { q.push(next); visited.insert(make_pair(next.y, next.z)); } } } cout << "无法得到目标容量的水" << endl; } int main() { int a, b, c, d; cout << "请输入三个水壶的容量(以空格分隔):"; cin >> a >> b >> c; cout << "请输入目标容量:"; cin >> d; solveThreeJugs(a, b, c, d); return 0; } ``` 这段代码使用了广度优先搜索算法来遍历所有可能的状态,直到找到目标容量的水或者无法得到目标容量的水。程序会输出一系列操作,其中X表示从x壶倒水,Y表示从y壶倒水,Z表示从z壶倒水。如果无法得到目标容量的水,则输出"无法得到目标容量的水"。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值