HZNU ACM寒假集訓Day7小結 揹包DP

2022-06-13 16:00:13 字數 3435 閱讀 7180

揹包問題 

01揹包

狀態:f(i,j) 表示只能裝前i個物品的情況下,容量為j的揹包所能達到的最大總價值

狀態轉移方程:  f(i,j)=max(f(i-1,j),f(i-1,j-w[i])+v[i])

核心**(滾動陣列) 由於我們使用一維陣列儲存,則在求兩個子問題時沒有直接取出那麼方便了,因為第i次迴圈可能覆蓋第i-1次迴圈的結果

「相反,如果在執行第 i 次迴圈時,揹包容量按照0..v的順序遍歷一遍,來檢測第 i 件物品是否能放。此時在執行第i次迴圈 且 揹包容量為v時,此時的f[v]儲存的是 f[i - 1][v] ,但是,此時f[v-weight[i]]儲存的是f[i][v-weight[i]]。

因為,v  > v - weight[i],第i次迴圈中,執行揹包容量為v時,容量為v - weight[i]的揹包已經計算過,即f[v - weight[i]]中儲存的是f[i][v - weight[i]]。即,對於01揹包,按照增序列舉揹包容量是不對的。」

for (int i = 1; i <= n; i++) 

}

但是,增序列舉會達到什麼效果:它會重複的裝入某個物體,而且盡可能的多使價值增大

01揹包方案數問題

洛谷p1164 小a點菜   

「開個玩笑,這是一道簡單的動規題,定義f[i][j]為用前i道菜用光j元錢的辦法總數,其狀態轉移方程如下:

(1)if(j==第i道菜的**)f[i][j]=f[i-1][j]+1;

(2)if(j>第i道菜的**) f[i][j]=f[i-1][j]+f[i-1][j-第i道菜的**];

(3)if(j《第i道菜的**) f[i][j]=f[i-1][j];

」code1

const

int maxn = 105

;int n, m, w[maxn], f[maxn][10010

];int

main()

for (int i = 0; i <= n; i++)

for (int i = 1; i <= n; i++)

}printf("%d

", f[n][m]);

return0;

}

view code

code2

const

int maxn = 105

;int n, m, w[maxn], f[100010

];int

main()

f[0] = 1

;

for (int i = 1; i <= n; i++)

}printf("%d

", f[m]);

return0;

}

view code

:完全揹包問題

狀態轉移方程: f(i,j)=max(f(i-1,j),f(i,j-w[i])+v[i])  理由是當我們這樣轉換時,f(i,j-w[i])已經由f(i,j-2*w[i]) 更新過,那麼f(i,j-w[i])就是充分考慮了第i件物品後的最優結果換言之,我們通過區域性最優子結構的性質重複使用了之前的列舉過程,優化了列舉的複雜度。

for (int i = 1; i <= n; i++) 

}

多重揹包問題 

考慮二進位制優化  

時間複雜度o(nwlog∑mi​)

luogu p1776 寶物篩選

#include#include

#include

#include

typedef

long

long

ll;using

namespace

std;

const

int maxn = 100505

;const

int maxm = 25005

;int n, m, ans, cnt = 1

;int

f[maxn];

intw[maxn], v[maxn];

intmain()

if (c) v[++cnt] = a * c, w[cnt] = b * c; //

二進位制優化 拆分

}

for (int i = 1; i <= cnt; i++)

}printf(

"%d\n

", f[m]);

return0;

}

hdu 2844 coins(多重揹包)

注意:本題只關注「可行性」

因此不妨變換思路求解

#include#include

#include

#include

typedef

long

long

ll;using

namespace

std;

int vis[100005

];int a[105

];int c[105

];int f[100005

];int

main() }}

int cnt = 0

;

for (int i = 1; i <= m; i++) if (f[i]) cnt++;

printf(

"%d\n

", cnt);

}return0;

}

分組揹包  (三重迴圈)

狀態轉移方程 f(k,v)=max(f(k-1,v),f(k-1,v-ci)+wi|i屬於group k)

時間複雜度o(nv)

hdu1712 acboy needs your help

#include#include

#include

#include

typedef

long

long

ll;using

namespace

std;

int mp[105][105

];int f[10005

];int

main()

}for (int i = 1; i <=n; i++) }}

printf(

"%d\n

", f[m]);

}return0;

}

初始化問題:

「初始化的f陣列事實上就是在沒有任何物品可以放入揹包時的合法狀態。

如果要求揹包恰好裝滿,那麼此時只有容量為0的揹包可能被價值為0的nothing「恰好裝滿」,其它容量的揹包均沒有合法的解,屬於未定義的狀態,它們的值就都應該是-∞了。

如果揹包並非必須被裝滿,那麼任何容量的揹包都有乙個合法解「什麼都不裝」,這個解的價值為0,所以初始時狀態的值也就全部為0了。」

HZNU ACM寒假集訓Day3小結 搜尋

簡單搜尋 1.dfs uva 548 樹 1.可以用陣列方式實現二叉樹,在申請結點時仍用 動態化靜態 的思想,寫newnode函式 2.給定二叉樹的中序遍歷和後序遍歷,可以構造出這棵二叉樹,方法是根據後序遍歷找到根,然後在中序遍歷中找到樹根,從而找出左右子樹的結點列表然後遞迴構造左右子樹 3.注意這...

寒假訓練 day7

vector容量和大小 include include using namespace std void printvector vector int v cout void test01 printvector v1 empty 操作 if v1.empty 1 else 重新指定大小 v1.re...

瀋陽集訓day7

吐槽 記錄 突然才知道自己太菜了,今天t1又因為輸出的時候少輸出了乙個換行符報零,加上就a,真傷心 linux換行和空格是乙個意思啊 t3正解過了 michael為救哥哥身陷囹圄,被關進foxriver監獄。為準備越獄,他需要散布訊息給監獄中其他人來共同協作,但是監獄中魚龍混雜,分成各個小團體,內部...