使用动态编程有限的活动选择

时间:2018-09-10 10:28:13

标签: c++ algorithm dynamic-programming

我正在学习动态编程,我解决了一些DP问题,但是我发现这对我的水平来说相当困难。对我来说,这个问题比简单的活动选择要困难得多。

因此,如果给定N个活动且每个活动中都包含“费用”,则选择最大活动数,则您的支出不能超过M金额。
1 <= N,M <= 10 ^ 5
1 <=开始<=结束<= 10 ^ 5
1 <=成本<= 10 ^ 5

例如,我们有5个活动和11个钱
格式:
从-到->费用
1-3-> 5
1-5-> 9
4-6-> 6
5-6-> 1
6-10-> 1
1-5、5-6、6-10 = 9 +1 +1 = 11
因此,答案是3个活动
当然,如果另一个答案具有相同的最大活动量:1-3、5-6、6-10,那么您可以选择任何想要的答案。
这是我的代码:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct temp{
    int from;
    int to;
    int cost;
};
using data = vector<temp>;

int f(data a, int len, int m){
    if (len<0 || m<0) return 0;
    int val=0;
    for (int i=0; i<len; i++){
        if (a[len].from >= a[i].to)
            val=max(val,f(a,len-i-1,m-a[len].cost)+1);
        else
            val=max(val,f(a,len-i-1,m)+1);//try another activity
    }
    return val;
}


int main(){
    data activity;
    int n,m;
    cin >>n >> m;
    for (int i=0; i<n; i++){
        int a,b,c;
        cin >> a >> b >> c;
        activity.push_back({a,b,c});
    }
    cout << f(activity,activity.size()-1,m);
}

我的代码有什么问题?我知道有几件事是错的,但我不知道在哪里。如何修复递归中的错误? 另外,如果可能,您可以使算法更快吗?无需更改自下而上的方法

1 个答案:

答案 0 :(得分:1)

我觉得这是加权活动问题和背包问题的混合问题。 这很困难,但非常有趣,并且是一个很好的学习机会。 我提议一个DP。以下帖子中的方法。 如果我弄错了什么,请有人纠正我。 然后,我希望进行建设性的讨论。


方法

首先,我们将活动标记为A = {a1, a2, .., aN},并按如下所示的时间整理活动:

  |----|a1
     |-----|a2
       |-------|a3 
           |-----|a4
                 ....

下一步

  • S(A,M)是活动A的{​​{1}}活动的最佳解决方案。

  • M严格位于元素L(a)左侧,A的所有活动 的a

    A

我们可以从最左边的活动example.) |----|a1 |-----|a2 L(a4)={a1, a2} |-------|a3 |-----|a4 .... 开始搜索S(A,M),然后进行最右边的活动a1。 对于每个活动aN,我们可以考虑其左侧区域ai

如果L(ai)是无限的,则在第M步中,iS(L(ai),M)的并集是最优解的候选。因此,子问题为ai。 在这一步中,我们已经有S(L(ai),M)S(a1,M),...,S({a1,a2},M)。 由于S({a1,...,a_i-1},M)是根据其整理时间排序的,因此我们可以将a1,...,aN作为其中之一或其中的一部分。 这种递归方法是当前问题的起点。

S(L(ai),M)

如果 example.) M=infinity |----|(a1,cost=2) subproblem of 1st step: S(L(a1),M)=empty |---|(a2,1) subproblem of 2nd step: S(L(a2),M)={a1} |----|(a3,2) subproblem of 3rd step: S(L(a3),M)={a1,a2} |--------|(a4,4) subproblem of 4th step: S(L(a4),M)={a1,a2}=S(L(a3),M) .... ^^^^^^^^^^ cached! 是有限的,则MS(L(ai),M-cost(ai))的并集是最优解的候选。因此,我们必须解决的不是ai而是S(L(ai),M)。 在这种情况下,不一定要缓存每个步骤中的子问题。

S(L(ai),M-cost(ai))

因此,在具有无限 example.) M=5 |----|(a1,2) subproblem of 1st step: S(L(a1),3)=empty |---|(a2,1) subproblem of 2nd step: S(L(a2),4)={a1} |----|(a3,2) subproblem of 3rd step: S(L(a3),3)={a1,a2} |--------|(a4,4) subproblem of 4th step: S(L(a4),1)={a2}!=S(L(a3),3) .... ^^^^^^^^ uncached! 的标准加权活动选择问题的情况下,我们始终可以专注于最活跃的活动组合。 但是在当前M有限的问题中,我们必须在递归步骤中缓存成本低于M的各种组合。


实施

记忆

适当的缓存表结构取决于M是否无限。 如果M是无限的,则一维高速缓存表足以执行动态编程。 但是,如果M是有限的,则需要二维缓存表。在您的示例中,它变为:

M

因此,我定义了以下缓存表类 end 3 4 5 6 10 <= end 1 | | | | [5,6] | [5,6],[6,10] | 2 | | | | [5,6] | [5,6]+[6,10] | money 3 | | | | [5,6] | [5,6]+[6,10] | 4 | | | | [5,6] | [5,6]+[6,10] | 5 |[1,3]|[1,3]|[1,3]|[1,3],[5,6]| [5,6]+[6,10] | 6 |[1,3]|[1,3]|[1,3]|[1,3]+[5,6]|[1,3]+[5,6],[1,3]+[6,10],[5,6]+[6,10]| ... ...

  • 缓存表CacheTable缓存std::map<std::pair<to,money>,Activities>> table_的元素。

  • S({a|a of A, a<=to},money)用于访问缓存表。

  • CacheTable::operator()用于在完成时间和金钱的约束下从缓存的结果中找到最佳解决方案。

我的快速实现如下:

CacheTable::getCachedOptimal

求解器

使用上面的缓存表,我们可以实现DP。当前问题的求解器如下。 该求解器只能找到struct activity { std::size_t from; std::size_t to; std::size_t cost; }; using Activities = std::vector<activity>; class CacheTable { // (to,money) --> cached optimal activities std::map<std::pair<std::size_t,std::size_t>, Activities> table_; public: Activities& operator()(std::size_t to, std::size_t money) { auto key = std::make_pair(to, money); auto it = table_.find(key); if(it == table_.cend()){ it = table_.emplace_hint(it, std::move(key), Activities()); } return it->second; } Activities getCachedOptimal(std::size_t to, std::size_t money) const { Activities cachedOptimal; for(auto it = table_.begin(); it != table_.cend(); ++it) { if((it->first.first <= to) && (it->first.second <= money)) { if(it->second.size() > cachedOptimal.size()){ cachedOptimal = it->second; } } } return cachedOptimal; } }; 的单个元素。 DEMO is here. 尽管这应该可行,但我认为有解决此问题的更有效方法。

S(A,M)