贪心过河问题

来源:互联网 发布:软件体系结构是什么 编辑:程序博客网 时间:2024/05/01 16:25
过河问题时间限制: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];elsesum = sum + s[1];printf("%d\n", sum);}return 0;}
0 0
原创粉丝点击