上次参加外校的校赛碰到的一道比较典型的贪心算法题。
题目大意是这样的:有n个人来接水,每个人的接水时间分别为t(i),现在一共有m个水龙头,问你n个人接水所需的最少时间。
我们首先可以想到m>=n和m=1这两种比较特殊的情况,对于m>=n的情况,每个人都可以单独用一个水龙头来接水,n个人无不影响,这时只需一个for循环,找出这n个人当中用时最长的那个人的接水时间输出即可;对于m=1的情况更简单,因为n个人都要接水,也就没有了先后之分,把n个人是接水时间加起来就行了;
那么接下来就是该问题的核心部分了,对于m<n的情况,我们怎么找出最短时间呢?
首先我们应该知道,要使接水的总时间最少,n个人当中用时最多的前m个人要分别占用不同的水龙头,这很好理解,因为m<n,所以肯定有至少两个人要用同一个水龙头来接水,那么这个水龙头所用的接水时间是这些时间的加和,如果这里面存在用时最长的前m个人中的一个的话,那么最后的用时肯定不是最优解。这样就好办了,我们先把n个人的接水时间按降序,然后定义一个s()数组来存放每一个水龙头所用的接水时间,并用排好序的前m个人的接水时间来初始化s()数组,对于从m+1开始的往后的每一个人,只需把他的接水时间加到s()数组里面最小的时间上,然后找出s()数组的最大值,即为n个人用m个水龙头接水所用的最短时间。
#include <iostream> #include <cstdio> #include <algorithm> #define MAX 1000 #define INF 999999999 using namespace std; int t[MAX],s[MAX]; int n,m; int cmp(const int &a,const int &b) { return a>b; } int find_min() { int pos,tmp=INF; for(int i=1;i<=m;i++) if(s[i]<tmp) { tmp=s[i]; pos=i; } return pos; } int main() { while(cin>>n>>m) { int i,ans=0; for(i=1;i<=n;i++) cin>>t[i]; if(m==1) { for(i=1;i<=n;i++) ans+=t[i]; } else if(m>=n) { for(i=1;i<=n;i++) if(t[i]>ans) ans=t[i]; } else { sort(t+1,t+1+n,cmp); for(i=1;i<=m;i++) s[i]=t[i]; for(;i<=n;i++) s[find_min()]+=t[i]; for(i=1;i<=m;i++) if(s[i]>ans) ans=s[i]; } cout<<ans<<endl; } return 0; }