矩阵(01背包+滚动数组)

题意:

有一个\(n×m\)的矩阵,你从左上角走到右下角,只能向下和向右走.每个点上有一个重量\(v_{i,j}\) 价值\(w_{i,j}\)的物品,你有一个容量为S的背包,经过一个点你可以将此点的物品放入背包,求最大能得到的价值.

分析:

\(f_{i,j,k}\)表示走到\((i,j)\),背包剩余容量为 k 时的最大价值.

\(f_{i,j}\)由\(f_{i-1,j}\)和\(f_{i,j-1}\)按普通 01 背包的方法转移.

时间复杂度 \(O(N^2V)\),空间复杂度 \(O(N^2V)\).因为\(400^3\)可能会爆空间MLE,所以我们可以按行或对角线滚动数组(我是按行滚动的),这样空间复杂度\(O(NV)\).

int n,m,S,ans;
int v[405][405],w[405][405],f[405][405];
//v重量,w价值
int main(){
    n=read();m=read();S=read();
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
        v[i][j]=read();
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
        w[i][j]=read();
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    for(int k=S;k>=0;k--){
        if(k>=v[i][j])f[j][k]=max(f[j][k],max(f[j][k-v[i][j]]+w[i][j],max(f[j-1][k],f[j-1][k-v[i][j]]+w[i][j])));
        else f[j][k]=max(f[j][k],f[j-1][k]);
    }
//因为题目中说了"只能向下和向右走",
//所以对于第i行的状态,一定只能由第i-1行转移得来,
//所以此时我们可以滚掉第一维i.
    for(int i=0;i<=S;i++)
        ans=max(ans,f[m][i]);
    printf("%d\n",ans);
    return 0;
}

滚动数组是动态规划,尤其是背包问题中很重要的一个思想,它虽然不能优化时间复杂度,但它能够减少空间复杂度.因为有时候可能题目会故意卡你的空间,所以我们要掌握好.

原文地址:https://www.cnblogs.com/PPXppx/p/10328090.html

时间: 2024-10-17 10:00:44

矩阵(01背包+滚动数组)的相关文章

poj3624 Charm Bracelet(0-1背包 滚动数组)

题目链接:https://vjudge.net/problem/POJ-3624 题意:有N个物品,分别有不同的重量Wi和价值Di,Bessie只能带走重量不超过M的物品,要是总价值最大,并输出总价值. 一开始使用正常的dp然后显示超内存,按下面代码也超内存(dp数组太大了)但这种方法可以学习一下 #include <iostream> #include <cstring> using namespace std; int n,m; //int w[3403],d[12881];

一道简单的递推题(快速幂+矩阵乘法优化+滚动数组)

问题 F: 一道简单的递推题 时间限制: 1 Sec  内存限制: 128 MB提交: 546  解决: 48[提交][状态][讨论版] 题目描述 存在如下递推式: F(n+1)=A1*F(n)+A2*F(n-1)+...+An*F(1) 求第K项的值对1000000007取模的结果 输入 单组测试数据 第一行输入两个整数 n , k (1<=n<=100,n<k<=10000000000) 第二行输入 n 个整数 F(1)   F(2)   ...   F(n) 第三行输入 n

c++01背包一维数组版及java多重背包

#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=1010; int c[maxn],w[maxn]; int dp[maxn]; int main(){ int n,v; cin>>n>>v; for(int i=1;i<=n;i++) cin>>c[i]; for(int i=1;i<=n;i++) cin>>w[i];

poj 3624 (01背包一维数组)

①这种问题要看清楚变量范围 数组范围很容易开错!!! ②这个下限是w[i]!!!很重要 或者加一句判断  if(j-w[i]>=0)  1 for(int i=1;i<=t;i++) 2 { 3 for(int j=n;j>=w[i];j--)//下限!!! 4 dp[j]=max( dp[j] , dp[j-w[i]]+v[i] ); 5 } AC代码,一维数组可以压缩空间. 1 #include <cstdio> 2 #include <cstring> 3

POJ3624(01背包:滚动 实现)

Charm Bracelet Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 30417   Accepted: 13576 Description Bessie has gone to the mall's jewelry store and spies a charm bracelet. Of course, she'd like to fill it with the best charms possible fro

ZOJ1366经典dp(多重背包转01背包+优化空间)

1 //zoj1366类似背包的问题 2 //争取一遍AC 3 #include<iostream> 4 #include<string.h> 5 #include<stdio.h> 6 #define maxn 13 7 using namespace std; 8 9 int k[maxn]; 10 int n1[maxn]; 11 int c1[maxn]; 12 int c2[105]; 13 int dp[110000]; 14 int Cash,N1,N2;

01背包、完全背包、多重背包

参考(都有些错误):https://github.com/guanjunjian/Interview-Summary/blob/master/notes/algorithms/%E7%BB%8F%E5%85%B8%E7%AE%97%E6%B3%95/01%E8%83%8C%E5%8C%85.mdhttps://blog.csdn.net/na_beginning/article/details/62884939 #include <iostream> #include <sstream&

01背包与物品无限背包

一.01背包问题 01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为C1,C2,…,Cn,与之相对应的价值为W1,W2,…,Wn.求解将那些物品装入背包可使总价值最大. 动态规划: 1) 子问题定义:F[i][j]表示前i件物品中选取若干件物品放入剩余空间为j的背包中所能得到的最大价值. 2) 根据第i件物品放或不放进行决策 其中F[i-1][j]表示前i-1件物品中选取若干件物品放入剩余空间为j的背包中所能得到的最大价值: 而F[i-1][j-C[i]]+W[i]表示前i-1

[CF837D] Round Subset(滚动数组,01背包)

题目链接:http://codeforces.com/contest/837/problem/D 题意:n个数里选k个数,使得它们的乘积末尾0个数最多. 只需要统计每个数的2和5的数量,一个作为容量,一个作为价值.f(i,k,j)表示前i个数选k个,一共有j个2的时候,5最多有几个. 外层枚举前i个数,内层做01背包就可以.但是会MLE,所以滚动数组. 特别注意的是,滚动数组在滚动的时候要拷贝整层,原因是我在更新01背包的时候没有及时复制... 还有f要注意当前层一定要从之前存在的状态更新过来,