动态规划 01背包问题

目前看到的01背包问题都不是递归方法解决的,应该是数量+容量的组合造成的特殊性质?

重点是理解状态转移方程。容量够了,可以选择放不放,如果放了会占据一定的容量,而剩余容量用来放其他的。

另外还有一个延申的问题,回溯所选组合。这里是逆序回溯,从最终状态dp[num][c]开始,用最大容量和物品[num-1]所需的容量比较,确定能放入再进行判断:是否有放入?有无放入物品i就看除去物品[num-1]之后的收益是否等于放了之后剩余容量的最大收益。其实就是上面的思路

template<class T>
class my_2DAry {
public:
    //typedef typename T value_type;
    T** pp;
    int m_l, m_c;
    my_2DAry(int l, int c):m_l(l), m_c(c) {
        pp = new T* [l];
        for (int i = 0; i < l; i++)pp[i] = new T[c];
    }
    ~my_2DAry() {
        if (pp != nullptr) {
            for (int i = 0; i < m_l; i++) {
                if (pp[i] != nullptr) {
                    delete[] pp[i];
                    pp[i] = nullptr;
                }
            }
            delete[] pp;
            pp = nullptr;
        }
        //cout << "my_2DAry destruct done" << endl;
    }
    void print() {
        for (int i = 0; i < m_l; i++) {
            for (int j = 0; j < m_c; j++)cout << pp[i][j] << ' ';
            cout << endl;
        }
    }
    bool setElem(int l, int c, int e) {
        if (l > m_l || c > m_c)return false;
        pp[l][c] = e;
        return true;
    }
    void init(T e) {
        for (int i = 0; i < m_l; i++)
            memset(pp[i], e, m_c*sizeof(T));
    }
};

int bag(int* w, int* p, int num, int c) {
    if (!w || !p || !num || !c)return 0;
    my_2DAry<int>dp(num + 1, c + 1);//为了方便计算dp中i-1=0的场景  //注意w[]和p[]从num=1开始
    dp.init(0);
    for (int i = 1; i <= num; i++) {
        for (int j = 1; j <= c; j++) {
            if (j < w[i - 1])dp.pp[i][j] = dp.pp[i - 1][j];//i-1可能为0
            else dp.pp[i][j] = std::max(dp.pp[i - 1][j], dp.pp[i - 1][j - w[i - 1]] + p[i - 1]);
        }
    }

    int* item = new int[num];
    auto func = [&dp, &w, &p, &item](int num,int c)->void{
        for (int i = num; i > 0; i--) {
            if (dp.pp[i][c] == dp.pp[i - 1][c])item[i - 1] = 0;
            else if (c - w[i - 1] >= 0 && dp.pp[i][c] == dp.pp[i - 1][c - w[i - 1]] + p[i - 1]) {
                item[i - 1] = 1;
                c -= w[i - 1];
            }
        }
    };//lambda也会析构以复制形式捕获的类,注意里面的指针成员
    func(num, c);
    for (int i = 0; i < num; i++)cout << item[i] << ' '; cout << endl;

    delete[] item;
    return dp.pp[num][c];
}

void test02() {
    int n = 4;
    int c = 8;
    int w[] = { 2 , 3 , 4 , 5 };
    int p[] = { 3 , 4 , 5 , 6 };
    cout << bag(w, p, n, c) << endl;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值