您的位置:首页 > 其它

贪心过河问题

2017-04-05 16:39 225 查看
过河问题
时间限制: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

----------
对于时间排序得到S(1) <= S(2) .... S(n-1) <= S(n)
/*贪心递归式:
首先由题目已知,无论单独过桥,还是两人一起过桥均需要手电筒,显然,当剩余未过桥的人数N > 1 ,是必定要两个一起过桥的,但过桥后,仍需要一个人送回手电筒,
显然送手电筒的人必须用时较短,因此我们选择S(1)送手电筒,而两个人一起过桥,显然为了用时最短,我们需要将剩余未过桥N人中用时最长的两个人S(N),S(N- 1)
先过桥,然后让S(1)送手电筒,但现在问题在于,由于只有一个手电筒,所以,让P,Q先过桥显然是不合理的,因为过桥后仍需送回手电筒,这就要求在P,Q过桥之前,
S(1)到达桥对面。
但我们再深入思考一下,若只让S(1)一人先过桥,然后再送回手电筒,显然也是不合理的,因为S(N - 1),S(N)过桥后,无人留在桥对面送回手电筒(我们尽量不让
时间较长的S(N - 1)和S(N - 1)送回手电筒),所以需要S(1)和S(2)一起过桥,然后S(1)送回手电筒,让S(N - 1)和S(N)过桥后,再由S(2)送回。以此类推。
这时,第一种方案出来了,即:sum1 = S(1) + 2 * S(2)+ S(N);
但我们再仔细分析可以发现,在这个方案中,S(1)必定存在,但由于具有2 * S(2),若S(2)相对较大时,(这是可能的,因为当剩余的人越来越少时,过桥时间越来越
接近)此时,第二种方案可能比第一种方案所需时间较短,即 sum2 = 2 * S(1) + S(N - 1) + S(N);此时,S(1)和S(N),S(N  - 1)一起过桥,且返回2次,我们可
以用sum2 - sum1 = S(1) + S(N - 1) - 2 * S(2);当S(1) + S(N - 1) < 2 * S(2)时方案二较优。
因此我们可得方程式:
 SUM = SUM + MIN(S(n - 1) + 2 * S(1) + S(n),S(n) + S(1) + 2 * S(2))
*/

----------

#include <stdio.h>
#include <stdlib.h>
#define MIN(a,b) ((a) > (b) ? (b) :(a))
int cmp(const void *a, const void *b)
{
return *(int *)a - *(int *)b;
}
int main()
{
int T, N;
int s[1001];
scanf("%d", &T);
while (T--)
{
scanf("%d", &N);
int i = 1, n = N;
while (N--)
{
scanf("%d", &s[i]);
++i;
}
qsort(s, i, sizeof(s[1]), cmp);
int sum = 0;
while (n > 3)
{
sum = sum + MIN(s[n - 1] + 2 * s[1] + s
, s
+ s[1] + 2 * s[2]);
n = n - 2;
}
if (n == 3)
sum = sum + s[1] + s[2] + s[3];
else if (n == 2)
sum = sum + s[2];
else
sum = sum + s[1];
printf("%d\n", sum);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: