more
闫氏dp分析法:
很重要的划分依据最后
1.
数字三角形 模型
时间复杂度:O( n 2 n^2 n2)
for(int i = 1;i <= n; i ++ ){
for(int j = 1; j <= i; j ++) cin>>a[i][j];
}
for(int i = 0; i <= n; i ++ ){
for(int j = 0; j <= i+1; j ++ ) dp[i][j] =-INF;
}
dp[1][1] = a[1][1];
for(int i = 2; i <= n; i ++ ){
for(int j = 1; j <= i; j ++ ) dp[i][j] =max(dp[i-1][j-1], dp[i-1][j]) + a[i][j];
}
4道eg题&&传送门
2.
最长上升子序列 模型(LIS
)
时间复杂度:O( n 2 n^2 n2)
for (int i = 1; i <= n; i ++ )
{
cin >> a[i];
f[i] = 1;
for (int j = 1; j < i; j ++ )
{
if (a[i] > a[j]) f[i] = max(f[i], f[j] + 1);
}
res = max(res, f[i]);
}
时间复杂度:O( n l o g n nlogn nlogn)
int len = 0;
dp[0] = -1e9;
for(int i = 1; i <= n; i ++ ){
if(dp[len] < a[i])dp[++len] = a[i], f[i] = len;
else {
int wz = lower_bound(dp+1, dp+1+len,a[i]) - dp;
dp[wz] = a[i];
f[i] = wz;
}
}
cout<<len<<endl;
eg题&&传送门
3.
背包问题
01背包
每件物品最多只使用一次。
for(int i=1; i<=n; i ++ ){
int v, w;
cin>>v>>w;
for(int j=m; j>=v; j--){
dp[j] = max(dp[j],dp[j-v]+w);
}
}
完全背包
每件物品可以使用无限次。
for(int i=1; i<=n; i++){
int v, w;
cin>>v>>w;
for(int j=0; j<=m; j++){
if(j>=v)dp[j] = max(dp[j],dp[j-v]+w);
}
}
多重背包
每件物品最多使用
s
[
i
]
s[i]
s[i] 次。
朴素写法
for(int i = 1; i <= n; i ++ ){
int v, w, s;
cin>>v>>w>>s;
for(int j=m; j >= 1; j--){
for(int k = 1; k <= s; k ++ ){
if(k*v<=j)dp[j] = max(dp[j],dp[j-k*v]+k*w);
}
}
}
O( n ∗ m ∗ l o g s n*m*logs n∗m∗logs)二进制优化,利用倍增的思想
cin>>n>>m;
for(int i = 1; i <= n; i ++ ){
int a, b, c;
cin>>a>>b>>c;
int k = 1;
while(k<=c){
v[cnt] = k*a;
w[cnt] = k*b;
cnt++;
c -= k;
k <<= 1;
}
if(c > 0){
v[cnt] = c*a;
w[cnt] = c*b;
cnt++;
}
}
for(int i = 0; i < cnt; i ++ ){
for(int j=m; j>=v[i]; j--){
dp[j] = max(dp[j], dp[j-v[i]]+w[i]);
}
}
cout<<dp[m]<<endl;
单调队列优化的分组背包O(nm)
# include <bits/stdc++.h>
using namespace std;
const int N = 2e4+10;
int q[N], f[N], g[N];
int n, m;
int main(){
cin>>n>>m;
for(int i = 1; i <= n; i ++ ){
int v, w, s;
cin>>v>>w>>s;
memcpy(g,f, sizeof f);
for(int j = 0; j < v; j ++ ){
int hh=0, tt=-1;
for(int k = j; k<=m; k += v){
if(hh<=tt && q[hh] < k -s*v)hh++;
while(hh<=tt && g[q[tt]] - (q[tt]-j)/v*w <= g[k] - (k-j)/v*w ) tt--;
q[++tt] = k;
f[k] = g[q[hh]] + (k - q[hh])/v*w;
}
}
}
printf("%d\n", f[m]);
return 0;
}
分组背包
每组中最多只可以选择一个物品。
cin>>n>>m;
for(int i = 0; i < n; i ++ ){
cin>>s[i];
for(int j = 0; j < s[i]; j ++ ){
cin>>v[i][j]>>w[i][j];
}
}
for(int i = 0; i < n; i ++ ){
for(int j = m; j >= 0; j -- ){
for(int k = 0; k < s[i]; k++){
if(j>=v[i][k])dp[j] = max(dp[j], dp[j-v[i][k]] + w[i][k]);
}
}
}