贪心算法(自顶向下,局部最优)

贪心算法(又称贪婪算法):在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题他能产生整体最优解或者是整体最优解的近似解。

贪心算法的基本思想

找出整体当中每个小的局部的最优解,并且将所有的这些局部最优解合起来形成整体上的一个最优解。

贪心选择性质

1.整体的最优解可以通过局部的最优解来求出;
2.一个整体能够被分为多个局部,并且这些局部都能够求出最优解。

使用贪心算法当中的两个典型问题是活动安排问题和背包问题。

贪心算法的基本步骤

1、从问题的某个初始解出发。
2、采用循环语句,当可以向求解目标前进一步时,就根据局部最优策略,得到一个部分解,缩小问题的范围或规模。
3、将所有部分解综合起来,得到问题的最终解。

经典案例:活动安排问题,背包等

背包问题

案例分析:平衡负载

2013年百度之星区域赛中的第一题”平衡负载”,主要就利用贪心进行分段,在我们理工的acm平台上有这道题,闲着也是闲着,贴出这道题自己的c++版本code。

平衡负载

Du熊正在负责一个大型的项目,目前有K台服务器,有N个任务需要用这K台服务器来完成,所以要把这些任务分成K个部分来完成,在同上台服务器上执行的任务必须是连续的任务,每个任务有各自需要的执行时间。 例如N=5,K=2,每个任务需要时间分别为5,3,1,4,7分钟,那么我们可以分成(5)(3 1 4 7)两部分,这样第一台服务器所花时间就是5分钟,而第二台机器需要花15分钟,当然,所有任务完成的时间是按最迟完成的那台服务器的时间,即这样划分的话完成所有任务所需要的时间就是15分钟。而另外一种划分方法是(5 3 1)(4 7),这种划分方案完成所有任务的时间就是11分钟,也是最优的一种划分方案。 现在你的任务就是根据给定的N,K和每个任务要花费的时间,找出使完成所有任务时间最短的方案。

输入:多组输入。

第一行输入N和K(1<=K<=N<=10000)。

第二行输入N个不大于1000的正整数,表示各个任要花费的时间。N=K=0表示输入结束。

输出:

每行输出一个整数,对应对于每个数据(除了N=K=0不用输出)。

样例输入:

5 1
5 3 1 4 7
5 2
5 3 1 4 7
5 3

算法实现code

#include<stdio.h>
#include<iostream>
using namespace std;
int a[10005];
bool check(int a[], int k,int m, int n) //数组,分k段,用来分段的m值,数组个数(检测m值是否可以将数组分为k段)
{
    int i,sum=0,count=0;
    for(i=0;i<n;i++)
    {
        sum+=a[i];//前i项求和
        if(sum>m) //若超过m值,则前i-1项分为一段,重新寻求下一段,同时段数加1
        {
            sum=a[i];
            count++;
        }
    }
    count++;//加上最后一段
    return count<=k;
}
int main()
{
    int i=0,j=0,n,k,l,r,mid=0;
    while(cin>>n>>k&&n!=0&&k!=0)
    {
       l=0;//最左边
       r=0;//最右边
       for(i=0;i<n;i++)
       {
           cin>>a[i];
           r+=a[i];
       }
       while(l<r)
       {
           mid=(l+r)/2;
           if(check(a,k,mid,n)) //m值分段数小于k,则要分段的m值应该减少,承受的项的个数更少,段数增加
           {
              r=mid;
           }
           else //m值分段数大于k,则要分段的m值应该增加,可承受更多项的和,段数减少
           {
              l=mid+1;
           }
       }
       printf("%d\n",l);//输出时间
    }
    return 0;
}