算法导论--贪心算法与动态规划(活动选择问题)

活动选择问题

有一个教室,而当天有多个活动,活动时间表如下:找出最大兼容活动集!活动已按结束时间升序排序.
算法导论--贪心算法与动态规划(活动选择问题)_第1张图片

动态规划

采用动态规划需要满足两个条件:1.最优子结构2.子问题重叠
Sij 表示在 ai 结束后和 aj 开始前活动的集合,假定 Aij 为活动集合 Sij 的最大兼容子集,其中包含活动 ak 。问题变成求 Sik Skj 最大兼容活动子集 Aik Akj z。我们用c[i,j]表示 Sij 的最优解的大小。
则c[i,j] = c[i,k]+c[k,j]+1;最后我们需要遍历所有可能的k值,找出最大的一个划分作为c[i,j],也即有子问题重叠问题。
即可以设计一个自底向上的算法,一步步到整个活动大小!
算法复杂度为O( n3 )

void Dynamic_Activity_Selector(int *s,int *f,int length)    //动态规划算法
{
    int c[13][13];              

    for (int m=0;m<12;m++)    //初始化数组。当i>j时,c[i][j]为空集
    {
        for (int n=0;n<=m;n++)
        {
            c[n][m] = 0;
        }
    }                                   
    int imax=0;
    for (int j=1;j<=length;j++)    //自底向上填写表c[i][j]
    {
      for (int i=j-1;i>=0;i--)
      {
          for (int k=i+1;kif (s[k]>=f[i] && f[k] <= s[j]) //检查划分点k是否满足条件
              {   
                  if (c[i][k]+c[k][j]+1 > c[i][j])
                  {   
                    c[i][j] = c[i][k]+c[k][j]+1;

                    if (k > imax)   //逐个输出 得到最大兼容子集
                    {
                        imax = k;
                        cout<

贪心算法

贪心算法的原理是在作出每个决策时,它在当时(局部)看来是最好的选择。作出一个贪心选择后,要求只剩下一个子问题。令 Sk 为在 ak 结束后开始的任务集合。对于活动选择问题,考虑局部最优时,作出一个决策前总是为以后的活动留下更多的时间,选择活动 ak 后,在 Sk 中选择最早结束的活动!所以第一次选择时,选择最早结束的活动,即是 a1 ,下一次在 S1 选择最早结束的活动.。
算法复杂度O(n)

迭代版本

void Greedy_Activity_Selector(int s[],int *f,int length)    //迭代贪心算法
{   
    int *A = new int[length];   //存储最大兼容子集
    if ( A == NULL)
        return;
    int i=0;
    A[i++]=1;
    int n=length;
    int k=1;
    for (int m=2;m<=n;m++)
    {
        if (s[m] >= f[k])
        {
            A[i++]=m;
            k=m;
        }
    }

    for(int j=0;j

完整代码

/************************************************************************
CSDN 勿在浮沙筑高台 
http://blog.csdn.net/luoshixian099
算法导论--贪心算法与动态规划(活动选择问题)
2015年6月18日                 
************************************************************************/
#include 
using namespace std;
void Recursive_Activity_Selector(int *s,int *f,int k,int n)  //递归贪心算法
{
    int m = k+1;
    while ( (m<=n) && (s[m]<=f[k]))    //选出满足活动的m
        m++;
    if (m <= n)
    {
        cout<//递归
    }
    else
        return;
}

void Greedy_Activity_Selector(int s[],int *f,int length)    //迭代贪心算法
{   
    int *A = new int[length];   //存储最大兼容子集
    if ( A == NULL)
        return;
    int i=0;
    A[i++]=1;
    int n=length;
    int k=1;
    for (int m=2;m<=n;m++)
    {
        if (s[m] >= f[k])
        {
            A[i++]=m;
            k=m;
        }
    }

    for(int j=0;jcout<delete []A;
}
void Dynamic_Activity_Selector(int *s,int *f,int length)    //动态规划算法
{
    int c[13][13];              

    for (int m=0;m<12;m++)    //初始化数组。当i>j时,c[i][j]为空集
    {
        for (int n=0;n<=m;n++)
        {
            c[n][m] = 0;
        }
    }                                   
    int imax=0;
    for (int j=1;j<=length;j++)    //自底向上填写表c[i][j]
    {
      for (int i=j-1;i>=0;i--)
      {
          for (int k=i+1;kif (s[k]>=f[i] && f[k] <= s[j]) //检查划分点k是否满足条件
              {   
                  if (c[i][k]+c[k][j]+1 > c[i][j])
                  {   
                    c[i][j] = c[i][k]+c[k][j]+1;

                    if (k > imax)   //逐个输出 得到最大兼容子集
                    {
                        imax = k;
                        cout<int main()
{
    int s[]={0,1,3,0,5,3,5,6,8,8,2,12,100};   //s[12]=100是为了动态规划的输出
    int f[]={0,4,5,6,7,9,9,10,11,12,14,16,101};
    int length = sizeof(s)/sizeof(s[0])-1;

    cout<<"Recursive_Activity_Selector:"<0,length-1);

    cout<<"Greedy_Activity_Selector:"<1);

    cout<<"Dynamic_Activity_Selector:"<return 0;
}

你可能感兴趣的:(Algorithm,算法导论--学习笔记)