过河问题

 

参考:http://www.clanfei.com/2013/05/1710.html

/*
过河问题
时间限制:1000 ms  |  内存限制:65535 KB 
难度:5
描述 
在漆黑的夜里,N位旅行者来到了一座狭窄而且没有护栏的桥边。如果不借助手电筒的话,大家是无论如何也不敢过桥去的。不幸的是,N个人一共只带了一只手电筒,而桥窄得只够让两个人同时过。如果各自单独过桥的话,N人所需要的时间已知;而如果两人同时过桥,所需要的时间就是走得比较慢的那个人单独行动时所需的时间。问题是,如何设计一个方案,让这N人尽快过桥。 

输入 
第一行是一个整数T(1<=T<=20)表示测试数据的组数
每组测试数据的第一行是一个整数N(1<=N<=1000)表示共有N个人要过河
每组测试数据的第二行是N个整数Si,表示此人过河所需要花时间。(0<Si<=100) 
输出 
输出所有人都过河需要用的最少时间 
样例输入 
1
4
1 2 5 10样例输出 
17

参考:http://www.clanfei.com/2013/05/1710.html
先将数组S按过河时间从小到大排好序。


1.当N为1时,答案自然直接为S1 
2.当N为2时,答案则是速度慢的一个,即S2 
3.当N为3时,由速度最快的与其中一个先过河,速度快的回来,再与另一个过河,时间为S1 + S2 + S3 
4.当N大于3时,问题开始变得复杂起来,我们需要寻找一个固定的规律,才能够将问题简单化,
  由于过桥需要有人将手电筒带回原岸,返程的必定是速度叫快的一个,即速度快的可能往返多次,
  因此由速度快的开始计算时间必然会非常复杂,而速度最慢的过河之后必定不会再回程,
  因此我们从速度慢的先考虑,先将速度慢的送过河。但此时可能出现两种情况:
  a.由于同时可以过两个人,因此可以考虑最快的与次快的过河,最快的回来,
    最慢的与次慢的过河,次快回来,以此节省次慢的过河时间,
	则最慢、次慢的过河时间为 S2 + S1 + Sn + S2 
  b.而另一种最容易考虑到的自然是最快的送最慢的过河,然后最快的回来,
    此时次慢变为最慢,再让最快的送其过河,最快再回来……
	那么最慢、次慢的过河时间为 Sn + S1 + Sn-1 + S1 

  即简化为送最慢的两个人先过河,在这两种情况中取花费时间最少的方式,规模缩小为n - 2的同一问题 

*/


#include <iostream>
using namespace std;

inline void mySweap(int&a,int&b)
{
	int temp=a;
	a=b;
	b=temp;
}

int getPos(int* p,int posBeg,int posEnd)
{
	int key=p[posEnd];
	int i=posBeg,j=posEnd-1;
	while ( j>=i ){
		while ( j>=i && p[j]>=key){
			--j;
		}
		while ( p[i]<key ){
			++i;
		}
		if ( i<j ){
			mySweap(p[i--],p[j--]);
		}
	}
	mySweap(p[i],p[posEnd]);
	return i;
}
//从小到大
void quickRank(int* p,int beg,int end)
{
	if ( beg<end ){
		int pos=getPos(p,beg,end);
		quickRank(p,beg,pos-1);
		quickRank(p,pos+1,end);
	}
}
void sulotion(const int *p,const int nSize)
{
	int leftPerson=nSize-1;
	int totalTime=0;
	while ( leftPerson>=3 ){

		totalTime+=(p[0]+2*p[1]+p[leftPerson])<(2*p[0]+p[leftPerson-1]+p[leftPerson]) 
			     ? (p[0]+2*p[1]+p[leftPerson]):(2*p[0]+p[leftPerson-1]+p[leftPerson]);
		leftPerson-=2;
	}
	if ( leftPerson==2 ){
		totalTime+=p[0]+p[1]+p[2];
	}
	if ( leftPerson==1 ){
		totalTime+=p[1];
	}
	if ( leftPerson==0 ){
		totalTime+=p[0];
	}
	cout<<totalTime<<endl;
}

int main()
{
	int a[1010];
	int num;
	cin>>num;
	while ( num-- ){
		int personNum;
		cin>>personNum;
		for ( int i=0 ; i<personNum ; ++i ){
			cin>>a[i];
		}
		quickRank(a,0,personNum-1);
		sulotion(a,personNum);
	}
	
	/*for ( int i=0 ; i<2 ; ++i ){
	cout<<a[i]<<"  ";
	if ( (i+1)%5==0 ){
	cout<<endl;
	}
	}*/
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值