紫薯第9章动态规划,从入门到入土(acwing部分)

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 nmlogs)二进制优化,利用倍增的思想

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]);
        }
    }
   
} 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值