算法导论16.1-1

算法导论16.1-1

题目要求为活动选择设计一个动态规划算法。

1. 问题描述
假定有一个n个活动的集合 S={a1,a2,...,an} ,这些活动使用同一个资源,而这个资源在某个时刻只能供一个活动使用。如果任务 ai 被选中,那么发生在 [si,fi) 期间。如果两个活动 ai aj 不重叠,即 sifj sjfi ,那么它们是兼容的。我们希望求解问题的一个最大兼容活动集(也就是元素最多的)。
2. 活动选择问题的最优子结构

Sij :在 ai 结束后开始,且在 aj 开始前结束的活动集合。也就是说 Sij 是不包含 ai aj 的。用数学的方法表示就是 s[p]f[i] f[p]s[j] ,其中 p Sij中元素的下标。
c[i,j] :集合 Sij 的最优解的大小。
假定 Aij Sij 的最优解,且 ap 为其中的活动,那么最优解 Aij 必定包含子问题 Sip Spj 的最优解,证明方法为剪切-粘贴法,此处从略。
于是乎, c[i,j] 可以得到如下递归式

c[i,j]=c[i,p]+c[p,j]+1

当不知道 Sij 的最优解包含的活动时,就需要比较 Sij 中所有的活动,因此
c[i,j]=0Sij=maxapSij{c[i,p]+c[p,j]+1}Sij

3. 计算最大兼容活动集的模
为了创建最优解,我们要跟踪 p 。算法只接受s f ,假设序列已经按f递增排好序,且 a0 an+1 已经在其中。我们用一个表 c[0..n,1..n+1] 来保存 c[i,j] 的值。第一维下标下届为0,第二维下标上届为n+1是因为 Sij 是不包含元素 ai aj 的。
另外,我们还需要一个表 k 来记录每次计算得到的ap的下标,以便于解的构造。伪代码的设计如下:

DYNAMIC-ACTIVITY-SELECTOR(s,f)
n=lenght(s)
s[n+1]=INT
f[n+1]=INT
for i=0 to n
    c[i,i+1]=0
    k[i,i+1]=-1
for l=1 to n      //Sij的元素个数
    for i=0 to n-l+1
        j=i+l+1
        c[i,j]=0
        k[i,j]=-1
        if f[i]<s[j]
            for p=i+1 to j-1
                if s[p]>=f[i] and f[p]<=s[j]
                    Kval=c[i,p]+c[p,j]+1
                if Kval>c[i,j]
                    c[i,j]=Kval
                    k[i,j]=p
return c and k

构造解的伪代码:

PRINT-SELECTOR(i,j)
if k[i,j]=-1
    return
print a k[i,j]
PRINT-SELECTOR(i,k[i,j])
PRINT-SELECTOR(k[i,j],j)

使用C++实现的程序:

#include<iostream>
#include<string>
#include<algorithm>
#define NUM 50
#define INT 65536
using namespace std;
int k[NUM][NUM];
int c[NUM][NUM];
int s[NUM];
int f[NUM];
void DYNAMIC_ACTIVITY_SELECTOR(int n)  //n is s's length
{
    s[n + 1] = INT;
    f[n + 1] = INT;
    for (int i = 0; i <= n; i++){
        c[i][i + 1] = 0;
        k[i][i + 1] = -1;
    }

    for (int l = 1; l <= n; l++){
        for (int i = 0; i <= n - l + 1; i++){
            int j = i + l + 1;
            c[i][j] = 0;
            k[i][j] = -1;
            if (f[i] < s[j]){   //is there room between i and j
                for (int p = i + 1; p <= j - 1; p++){
                    if (s[p] >= f[i] && f[p] <= s[j]){
                        int Kval = c[i][p] + c[p][j] + 1;
                        if (Kval>c[i][j]){
                            c[i][j] = Kval;
                            k[i][j] = p;
                        }
                    }
                }
            }
        }
    }
}

void PRINT_SELECTOR(int i, int j)
{
    if (k[i][j] == -1)
        return;
    cout << "a" << k[i][j]<<" ";
    PRINT_SELECTOR(i, k[i][j]);
    PRINT_SELECTOR(k[i][j], j);
}
void main()
{
    for (int i = 1; i <= 11; i++)
        cin >> s[i];
    for (int i = 1; i <= 11; i++)
        cin >> f[i];
    DYNAMIC_ACTIVITY_SELECTOR(11);
    PRINT_SELECTOR(0, 12);
    cout << endl;
}

4.运算结果展示
这里写图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值