2015-03-07,海盗问题----google面试第八关水平

3 篇文章 0 订阅
3 篇文章 0 订阅

今天继续c++,过了最后一个知识点也就是异常,try,catch,throw,其中try,catch是用来捕获异常的,throw用来抛异常的,自我感觉这个还是要和项目结合起来,但说的话真的没什么,比如异常和模板在一起的时候。等等。今天还过了过一些面试题,为过一阵子招工作做准备吧,今天我们还是主要说海盗问题吧,今天接触到了一点算法的问题。

海盗问题,据说是google面试第8关的水平哦~

题目如下:10名海盗抢得了窖藏的100块金子,并打算瓜分这些战利品。这是一些讲民主的海盗(当然是他们自己特有的民主),他们的习惯是按下面的方式进行分配:最厉害的一名海盗提出分配方案,然后所有的海盗(包括提出方案者本人)就此方案进行表决。如果50%或更多的海盗赞同此方案,此方案就获得通过并据此分配战利品。否则提出方案的海盗将被扔到海里,然后下提名最厉害的海盗又重复上述过程。所有的海盗都乐于看到他们的一位同伙被扔进海里,不过,如果让他们选择的话,他们还是宁可得一笔现金。他们当然也不愿意自己被扔到海里。所有的海盗都是有理性的,而且知道其他的海盗也是有理性的。此外,没有两名海盗是同等厉害的——这些海盗按照完全由上到下的等级排好了座次,并且每个人都清楚自己和其他所有人的等级。这些金块不能再分,也不允许几名海盗共有金块,因为任何海盗都不相信他的同伙会遵守关于共享金块的安排。这是一伙每人都只为自己打算的海盗。最凶的一名海盗应当提出什么样的分配方案才能使他获得最多的金子呢?  


这个问题首先我们要想明白,我们想明白后还要分析出每一个步骤,然后让计算机也想明白。我们一点一点的来,

如果只有2个海盗的时候,不管2号海盗说什么,1号海盗都不同意,是不是2号海盗就肯定会被扔到海里呢,剩下的金子肯定就是1号的了。

如果只有3个海盗的时候,是不是不管3号海盗说什么,2号海盗都会同意呢,因为如果2号不同意,1号也不同意,3号海盗被扔进海里后紧接着自己是不是也就该被扔进海里呢。所以3号海盗知道,2号海盗想活命必须全力支持我,就会出来一个很猥琐的分配方式,100,0,0 。

如果有4个海盗的时候呢,现在到了关键的时刻了,4号海盗要满足要让除自己之外还有两个人支持自己呢,如果4号被扔下海,那么就会变成有3个海盗的情况,所以4号要至少给2个人好处,至少每个人要多一块金子对吧,那么如果是3个海盗的情况下,是100,0,0,那么4号肯定就给1,2号两个兄弟一人多一块,以便于这两个兄弟要支持我对吧,既然给他们1人1块了,自己也就只有98块金子了,所以4个人的时候就是98,0,1,1

如果有5个海盗的时候呢,我们再推理这一层,5号海盗知道自己如果被推下水之后,那么剩下的就会98,0,1,1这样分了对吧,所以5号海盗要比4个人的时候给2个人多一块金子,别人的就不管了,可以统统的归自己,4个人的时候是98,0,1,1,那么为了利益最大化,3号肯定要加一个,因为他本来就没有金子,你给他一块,他就高兴了,剩下1,号和2号,你随意吧,只能给一个人就行了,其他人全都没有(假设我们给1号),结果就会这么分,97,0,1,0,2,5号海盗自己有97块金子。

推理过程如图:

下面把代码粘过来供大家参考吧,亲自写的,有问题希望大家纠正:


#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int minGoldAddOneAndClearOther(int num, vector<int> & vec)
{
	//创建一个指针数组,这个数组每个对象是个指针,指向数据
	vector<int *> pvec(vec.size());
	for (int i = 0; i < vec.size(); i++)
	{
		pvec[i] = &vec[i];
	}
	//排序,计算出来可以给谁最少的金子
	for (int i = 0; i < pvec.size(); i++)
	{
		for (int j = i; j < pvec.size(); j++)
		{
			if (*(pvec[i]) > *(pvec[j]))
			{
				int *temp = pvec[i];
				pvec[i] = pvec[j];
				pvec[j] = temp;
			}
		}
	}
	//给至少支持我的人每个人比上一个人多一块,然后不支持的人的金子统统清零,归为己有
	int res = 0;
	for (int i = 0; i < pvec.size(); i++)
	{
		if (i < num)
		{
			(*pvec[i])++;
			res += (*pvec[i]);
		}
		else 
		{
			(*pvec[i]) = 0;
		}
	}
	//返回给这些支持我的人的总金子数
	return res;
}


void getGoldFunction(int mans, int gold, vector<int> & vec)
{
	//如果是3个人就这么分,100,0,0
	if (mans == 3)
	{
		vec.insert(vec.begin(), 0);
		vec.insert(vec.begin(), 0);
		vec.insert(vec.begin(), 100);
		return;
	}
	else
	{
		//计算出最少支持我的人数(包括我自己)
		int minzhichi = 0;
		minzhichi = 1 + mans / 2;
		//计算出如果我被扔进海里,那么下一个人怎么分,结果在vec里面
		getGoldFunction(mans - 1, gold, vec);
		//计算出来给那些支持我的人最少多少块金子,
		int othergold = minGoldAddOneAndClearOther(minzhichi - 1, vec);
		//计算出我的金子
		int mygold = gold - othergold;
		//插入vector
		vec.insert(vec.begin(), mygold);
	}
}



void main()
{
	int gold = 100;
	int mans = 100;
	vector<int> res;
	//把最后的分配方式存在res里
	getGoldFunction(mans, gold, res);
	for (int i = 0; i < res.size(); i++)
	{
		cout << res[i] << "  ";
	}
	cout << endl;
	cin.get();
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值