1. 程式人生 > >分組揹包及樹上分組揹包

分組揹包及樹上分組揹包

【人生相關】好睏啊QAQ 小夥伴們明天都去APIO了 當初腦殘沒報名= = 蠻後悔的= = 但想想2800rmb 也就還好了
美好的一天從一道樹形dp開始
昨天看了下以前寫的分組揹包 樹形dp
分組揹包是說有n組物品 每個組別只能選一個 體積限制V 的最大價值w
先考慮二維:

//f[i][j] 表示 前i組體積為j的最大價值
//j k 迴圈可顛倒
for(int i=1;i<=N;i++) //組別
    for(int k=1;k<=n[i];k++) //每個物品
        for(int j=V;j>=0;j--) //體積
            f[i][j]=min
(f[i][j],f[i-1][j-v[i][k]]+w[i]);

一維
k在j裡 j倒迴圈 因為f[j]是由f[j-x]更新的 準確的說是f[i-1][j-x] k在裡迴圈是要每次準確地更新出f[j]的值(k在裡側時 是沒迴圈完一個i才準確更新出f[j]) 而j倒迴圈是因為每次計算f[j]時 用到的是f[i-1][j-x] 即未更新過的f[j-x] 正迴圈的話 都更新過了

//k在j裡 j倒迴圈
for(int i=1;i<=N;i++) //組別
    for(int j=V;j>=0;j--) //體積
        for(int k=1;k<=n[i];k++) //每個物品
f[j]=min(f[j],f[j-v[i][k]]+w[i]);

要我說 還有另一種寫法

for(int i=1;i<=N;i++) //組別
    for(int j=V;j>=0;j--){ //體積
        for(int k=1;k<=n[i];k++) //每個物品
            f[i&1][j]=min(f[i&1][j],f[(i-1)&1][j-v[i][k]]+w[i]);
        memset(f[(i-1)&1],0,sizeof(f[(i-1)&1]));
    }

一道樹(N)上分組揹包 就是把每棵子樹看成一個分組 每棵子樹選取不同個數(or?)個節點看成每個揹包中不同的物品(每個分組中只能選一個物品) 體積限制V相當於總結點數限制 這樣每個節點做一次分組揹包 所有節點加在一起一共有N個分組 每個組裡最多有N個物品 體積限制V最多是N 時間複雜度O(N^3)
f[i&1][j]=min(f[i&1][j],f[(i-1)&1][j-v[i][k]]+w[i]);
memset(f[(i-1)&1],0,sizeof(f[(i-1)&1]));