贪心过河问题

过河问题
时间限制: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[n], s[n] + 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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值