链接 :http://poj.org/problem?id=1700
http://acm.nyist.net/JudgeOnline/problem.php?pid=47
Description
Input
Output
Sample Input
1 4 1 2 5 10
Sample Output
17
思路分析 :
当n=1,2,3时所需要的最小时间很容易求得,现在由n>=4,假设n个人单独过河所需要的时间存储在数组t中,将数组t按升序排序,即数组中所表示的时间是递增的.
那么这时将单独过河所需要时间最多的两个旅行者送到对岸去,有两种方式:
1> 最快的(即所用时间t[0])和次快的过河,然后最快的回来,再次慢的和最慢的过河,然后次快的回来.
2> 最快的和最慢的过河,然后最快的回来,再最快的和次慢的过河,然后最快的回来.
这样就将过河所需时间最大的两个人送过了河,而对于剩下的人,采用同样的处理方式,接下来做的就是判断怎样用的时间最少.
1> 方案1所需时间为:t[0]+2*t[1]+t[n-1];
2> 方案2所需时间为:2*t[0]+t[n-2]+t[n-1];
如果方式1优于方式2,那么有:t[0]+2*t[1]+t[n-1]<2*t[0]+t[n-2]+t[n-1] 化简得:2*t[1]<t[0]+t[n-2]
即此时只需比较2*t[1]与t[0]+t[n-2]的大小关系即可确定最小时间,此时已经将单独过河所需时间最多的两个人送过了河,那么剩下过河的人数为:n-=2,采取同样的处理方式.
(注意:此题的贪心策略是动态的!!!)
代码如下:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define MAXN 1000 //最多人数
#define RST(N)memset(N, 0, sizeof(N))
using namespace std;
int s[MAXN];
int cmp(const void *a, const void*b) //按时间从小到大排序
{
return *(int *)a - *(int *)b;
}
int main()
{
int cas, n, k, st, a, b;
scanf("%d", &cas);
while(cas--) {
scanf("%d", &n);
for(int i=0; i<n; ++i) {
scanf("%d", &s[i]);
}
qsort(s, n, sizeof(int), cmp);
if(n == 1 || n == 2) {
printf("%d\n", s[n-1]);
continue;
}
st = 0;
if(n % 2) { //最后一次过河所需的时间,分为奇数和偶数两种情况
st+= s[0] + s[1] + s[2];
}else {
st+= s[1];
}
k = (n - 2) / 2; //贪心的次数
for(int i=0; i<k; ++i) { //贪心的策略
a= s[0] + 2 * s[1] + s[n-1];
b= 2 * s[0] + s[n-1] + s[n-2];
if(a < b) {
st += a;
}else {
st += b;
}
n -= 2;
}
printf("%d\n", st);
}
return 0;
}