揹包問題
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
constview codeint 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;
}
code2
constview codeint 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;
}
:完全揹包問題
狀態轉移方程: 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#includehdu 2844 coins(多重揹包)#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;
}
注意:本題只關注「可行性」
因此不妨變換思路求解
#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監獄。為準備越獄,他需要散布訊息給監獄中其他人來共同協作,但是監獄中魚龍混雜,分成各個小團體,內部...