微软过桥问题Dijkstra/倒水问题

微软过桥问题

    微软的过桥问题:4个人在晚上过一座小桥,过桥时必须要用到手电筒,只有一枚手电筒,每次最多只可以有两人通过, 4个人的过桥速度分别为1分钟、2分钟、5分钟、10分钟,试问最少需要多长时间4人才可以全部通过小桥?

思路:刚一看到这道题,思路比较狭窄,就拿着笔把人移过来再移过去,第一次做出的答案是19(错误答案).后来上网上去找参考答案,发现是17.网上的答案只给出得到17分钟的解决方式,并没有说出到底应该怎么样解这个答案才能百分百确定就是最少的长时?因此,开始乱想:穷举法,贪心法,参考《牧师与野人过河问题》,DFS,图论找最小路径法,乱蒙。最开始参照<牧师与野人>的算法,发现,无果。再用穷举法,发现转移状态实在太多,没有办法递归下去,然后用贪心选择,发现最后倒在vector.erase上面了,而且递归的时候没有办法恢复现场,因为需要在vector的中间删除一个元素,然后再恢复,并不像《字符串全排列》那样可以push_back,再pop_back就能恢复现场。最后想,既然无法恢复现场,那么不妨可以从一开始就不要破坏原来现场,而只是拷贝原来vector的一份拷贝,只对拷贝进行操作,那么递归返回时就没有必要恢复原来现场,当然原来现场也并没被破坏,这样一来,每次递归结束之后,我们可以得到一个过桥方案,递归堆栈中的内容被清除(当然对原来内容并没有任何影响,下一次可以继续正常递归而不需要担心原来内容被改变而带来的不确定后果)。其于这个方案可以得到下面的程序(贪心法)。

 

#include<vector>
#include<iostream>
using namespace std;

void removeKeyFromVec(vector<int>& veci,int key)
{
	for(vector<int>::iterator iter=veci.begin(); iter!=veci.end(); ++iter)
	{
		if( *iter == key)
		{
			iter = veci.erase(iter);//erase的使用要小心
			return ;
		}
	}
}

void CrossBridge(vector<int>& src, vector<int>& des, int size, int TimeSum)
{
	//程序出口,当只有2个人时,直接过桥
	if(size == 2)
	{
		cout<<"A->B:"<< src[0] << " AND " << src[1]<<endl;
		cout<<"Time : "<<TimeSum + max(src[0], src[1]) <<endl;
		cout<<endl;
		return ;
	} 
	//从size大小的数列中找出两个数的组合,例1,2,5有(1,2),(1,5),(2,5) 3种组合
	for(int i=0; i<size; i++)
	{
		for(int j=i+1; j<size; j++)
		{
			cout<<"i="<<i<<" j="<<j<<endl;
			//只操作src的拷贝,否则递归之后需要还原现场,较麻烦
			vector<int> srcTemp(src) ;
			vector<int> desTemp(des) ;
			
			int goTime1 = srcTemp[i] ;
			int goTime2 = srcTemp[j] ;
			//2人过桥
			desTemp.push_back(goTime1);
			desTemp.push_back(goTime2) ;

			cout<<"A->B: " << goTime1 <<" AND "<< goTime2 <<endl;

			removeKeyFromVec( srcTemp ,goTime1);
			removeKeyFromVec( srcTemp ,goTime2);

			int minBackTime = desTemp[0];
			for(int k=0 ; k<desTemp.size(); k++)
			{
				if( desTemp[k] < minBackTime)
				{
					minBackTime = desTemp[k];
				}
			}
			//1人返回
			
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Raise

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值