n个人用m个水龙头的接水问题 贪心

上次参加外校的校赛碰到的一道比较典型的贪心算法题。

题目大意是这样的:有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;
}

你可能感兴趣的:(n个人用m个水龙头的接水问题 贪心)