算法导论16.1-1

本文介绍了一种利用动态规划算法解决活动选择问题的方法。针对一组活动,目标是找出最大的兼容活动子集,使得这些活动不会在同一时间段内冲突。文章详细阐述了最优子结构的概念,并给出了解决该问题的具体动态规划算法。

算法导论16.1-1

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

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

Sij:在ai结束后开始,且在aj开始前结束的活动集合。也就是说Sij是不包含aiaj的。用数学的方法表示就是s[p]f[i]f[p]s[j],其中pSij中元素的下标。
c[i,j]:集合Sij的最优解的大小。
假定AijSij的最优解,且ap为其中的活动,那么最优解Aij必定包含子问题SipSpj的最优解,证明方法为剪切-粘贴法,此处从略。
于是乎,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。算法只接受sf,假设序列已经按f递增排好序,且a0an+1已经在其中。我们用一个表c[0..n,1..n+1]来保存c[i,j]的值。第一维下标下届为0,第二维下标上届为n+1是因为Sij是不包含元素aiaj的。
另外,我们还需要一个表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
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值