题目描述
n
个人要过一座桥,只是在漆黑的夜里,没有火把显然是不行的。但是这n
个人只有一个火把,并且这座桥每次最多只能通过两个人。
每个人的速度不同,若两人组队,队伍速度等于较慢一人的速度。你要做的是计算这n
个人全部通过这座桥的最少时间。
输入
多组输入。每组数据的第一行是输入一个n
,代表有n(1 <= n && n <= 500)
个人,接下来的n
个整数,代表着每个人穿过这座桥所需要的时间。
输出
输出一个整数,代表最优策略所需时间sum
。
示例输入
4
1
10
5
2
示例输出
17
提示
假设人员编号按输入顺序从1
到n
,首先编号为1,4
的人通过,编号为1
的回来送火把,然后编号为2,3
组队通过,编号为4
的回来送火把,编号为1,4
通过,结束。
sum = 2 + 1 + 10 + 2 + 2 = 17。
思路:
把每个人过桥的时间排序,每次都使用过桥时间最短的两个人把过桥时间最长的两个人送过桥。假设left = [a,b,..]
表示桥左边的人,right = [a,b,...]
表示桥右边的人。
假设时间最短的两个人的过桥时间为a,b
,时间最长的两个人为x,y
,其中a < b < x < y
则过桥方式有两个思路:
方式一:
让这四个人当中时间最短的人护送时间最长的两个人过河,状态为:
状态 时间
left = [b, x] right = [a, y] y
left = [a, b, x] right = [y] a
left = [b] right = [a, x, y] x
left = [a, b] right = [x, y] a
// 总时间
sum += y + a + x + a = 2 * a + x + y
方式二:
让四个人当中时间最长的人一起过河,则节约了次长的人的时间,状态为
状态 时间
left = [x, y] right = [a, b] b
left = [a, x, y] right = [b] a
left = [a] right = [b, x, y] y
left = [a, b] right = [x, y] b
// 总时间
sum += b + a + y + b = 2 * b + a + y
由方式一和方式二可知,在每次使用时间最短的人把时间最长的人运过河的时候,需要进行比较,看看选择方式一还是方式二更加节约时间,若方式一更快,则有2 * a + x + y < 2 * b + a + y
,化简得2 * b > a + x
。
如果2 * b > a + x
,则有sum += 2 * a + x + y
;
如果2 * b <= a + x
,则有sum += 2 * b + a + y
还没有过河的人数小于4的时候,考虑n=1,2,3
的情况:
当n = 1
时,直接过河,时间为a
;
当n = 2
时,直接两人一起过河,时间为b
;
当n=3
时,假设人为a, b, x
,则有:
状态 时间
left = [b] right = [a, x] x
left = [a, b] right = [x] a
left = [] right = [a, b, x] b
// 总时间
sum = a + b + x
过河时间为a + b + x
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int main()
{
int i, j, n, num[1000], a, b, x, y;
while(cin >> n)
{
for(i=0; i<n; i++) {
cin >> num[i];
}
sort(num, num + n);
int sum = 0;
while(n >= 4)
{
a = num[0];
b = num[1];
x = num[n - 2];
y = num[n - 1];
if(2 * b < a + x)
{
sum += 2 * b + a + y;
n -= 2;
}
else
{
sum += a * 2 + x + y;
n-=2;
}
}
if(n == 3) {
sum += num[0] + num[1] + num[2];
}
else if (n<=2) {
sum+=num[n-1];
}
cout<< sum <<endl;
}
return 0;
}