原文链接:NYOJ-47-过河问题
题目大意:
描述
在漆黑的夜里,N位旅行者来到了一座狭窄而且没有护栏的桥边。如果不借助手电筒的话,大家是无论如何也不敢过桥去的。不幸的是,N个人一共只带了一只手电筒,而桥窄得只够让两个人同时过。如果各自单独过桥的话,N人所需要的时间已知;而如果两人同时过桥,所需要的时间就是走得比较慢的那个人单独行动时所需的时间。问题是,如何设计一个方案,让这N人尽快过桥。
解题思路:
根据人数的不同需要分情况考虑,一下一位博主的分析,直接粘贴了过来,侵删。直接看代码中的注释也可以。
当n==1或者n==2时:所有人直接过河即可。
当n==3时:用时最长和用时最短的人先一起过去,然后用时最短的人回来,再在和剩下的一个人一起过去。
当n==4时:假设time[0]为用时最短的人所用的时间,time[1]为用时第二短的人所用的时间, time[n-1]为用时最长的人所用的时间, time[n-2]为用时第二长的人所用的时间。则有两种过河方式:
2*time[0]+time[n-1]+time[n-2]表示:用时最长的人和用时最短的人先一起过去,然后用时最短的人把手电筒带回来,再和用时第二长的人一起过去,用时最短的人回来。
2*time[1]+time[0]+time[n-1]表示:用时最短和用时第二短的人一起过去,然后用时最短的人把手电筒带回来,然后用时最长和用时第二长的人一起过去,用时第二短的人回来。
比较两种过河方式:2*time[0]+time[n-1]+time[n-2]<2*time[1]+time[0]+time[n-1] 这样相当于每次都过去了两个人,所以n-=2, 再对剩下的n-2个人执行相同的操作,直至不足4人即可。
代码:
#pragma warning(disable : 4996)
#include<iostream>
#include<algorithm>
#include<math.h>
#include<cstring>
#include<string>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define LOCAL
using namespace std;
const int MAXN = 1000 + 10;
int t[MAXN],n,m;
int main()
{
#ifdef LOCAL
// freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif
cin >> m;
while(m--){
cin >> n;
int sum=0;
for(int i = 0;i<n;i++) cin >> t[i];
sort(t,t + n);
while(n >= 4){
//以下两种方式,每次运过去两个人,比较两种方式,看哪一种时间段就选哪一种
//时间最短的两个t[0],t[1]先过去,然后t[0]带着手电筒回来,
//然后时间最长的两t[n-1],t[n-2]再过去,然后让t[1]把手电筒送回来
int tm1 = t[1] + t[0] + t[n-1] + t[1];
//最快的t[0]和最慢的t[n-1]先过,然后t[0]把手电筒带回来,
//然后第二慢的t[n-2]和t[0]一起过去,然后t[0]再把手电筒带回来
int tm2 = t[n-1] + t[0] + t[n-2] + t[0];
sum += tm1 < tm2 ? tm1 : tm2;
n -= 2;
}
//只有三个人时,最快的和最慢的一起过,之后最快的把手电筒带回来,再和中间的一起过
if(n==3) sum += t[0] + t[1] + t[2];
//只有两个或一个人时直接过
if(n==2) sum += t[1];
if(n==1) sum += t[0];
cout<< sum<<endl;
}
return 0;
}