常用背包dp模板(未完待续)
这里是作者的留言板
部分板子优化中...;
你好哇,我是flypig114;
先说一句:本人仅在博客园发表博客,其他皆为盗版;
可能某些人能看出上面那句是什么意思,我也不多说了;
代码里有变量(只不过最近会改变量名使其更正规)数组的注释,so...不多废话,直接上正题!;
01背包
这里是题目AWA:
有\(N\)件物品和一个容量是\(M\)的背包。每件物品只能使用一次。第 \(i\)件物品的体积是\(w\),价值是\(v\)。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。输入格式
第一行两个整数,\(N\),\(M\),用空格隔开,分别表示物品数量和背包容积。接下来有 \(M\)行,每行两个整数\(wi\),\(vi\),用空格隔开,分别表示第\(i\)件物品的体积和价值。输出格式
输出一个整数,表示最大价值。
数据范围
\(0<M,N≤10000\)
\(0<vi,wi≤10000\)
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例
8
无优化
#include<bits/stdc++.h>
using namespace std;
#define ll int // 为了方便修改类型
const ll N = 1000; // 辅助定义数组
ll n, m; // n是物品数量 m是背包容量
ll v[N], w[N]; // v是物品的价值 w是物品的重量
ll i, j, dp[N][N]; // 辅助计算,dp[i][j]表示前i个物品放入容量为j的背包的最大价值
int main()
{
//背包与DP的开始
cin >> n >> m;
for (i = 1; i <= n; i++)
{
cin >> w[i] >> v[i];
}
//进行处理
for (i = 1; i <= n; i++)
for (j = m; j >= 0; j--)//从背包容量开始,保证每个物品都考虑过
{
if(j>=w[i])//判断是否可以放入
{
dp[i][j] = max(dp[i - 1][j - w[i]] + v[i], dp[i - 1][j]);//判断是否放入,dp[i-1][j-w[i]]+v[i]更大则放入
}
else
{
dp[i][j] = dp[i - 1][j];//不放入
}
}
//结束首战告捷
cout << dp[n][m];
return 0;
}
一维数组优化
#include<bits/stdc++.h>
using namespace std;
#define ll int//为了方便修改类型
const ll N=1e5;//辅助定义数组
ll n, m; // n是物品数量 m是背包容量
ll v[N], w[N]; // v是物品的价值 w是物品的重量
ll i, j, dp[N]; // 辅助计算
int main()
{
//难度上升需要新方法
cin >> n >> m;
for (i = 1; i <= n; i++)
{
cin >> w[i] >> v[i];
}
//重中之重(好像就这里改了)
for (i = 1; i <= n; i++)
{
for (j = m; j >= 0; j--)
{
if(j>=w[i])
{
dp[j] = max(dp[j - w[i]] + v[i], dp[j]);
}
}
}
//可以输出了
cout << dp[m] << endl;
return 0;
}
完全背包问题:
这里是题目AWA:
有\(M\)件物品和一个容量是\(N\)的背包。每件物品可使用无限次。第\(i\)件物品的体积是\(v\),价值是\(w\)。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。输入格式
第一行两个整数,\(N\),\(M\),用空格隔开,分别表示背包容积和物品数量。接下来有 \(M\)行,每行两个整数\(vi\),\(wi\),用空格隔开,分别表示第\(i\)件物品的体积和价值。输出格式
输出一个整数,表示最大价值。
数据范围
\(0<M≤30,0<N≤200\)
\(0<vi,wi≤10000\)
输入样例
10 4
2 1
3 3
4 5
7 9
输出样例
12
#include<bits/stdc++.h>
using namespace std;
#define ll int // 为了方便修改类型
const ll N = 1e5; // 辅助定义数组
ll n, m; // n是背包容量 m是物品数量
ll v[N], w[N]; // v是物品的重量 w是物品的价值
ll dp[N], i, j; // 辅助计算
int main(){
cin >> n>> m;
// 输入
for (i = 1; i <= m; i++)
{
cin >> v[i] >> w[i];
}
//完全背包启动!
for (i = 1; i <= m; i++)
{
for (j = 0; j <= n; j++)
{
if (j >= v[i])
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
}
}
//简简单单的输出
cout << dp[n] << endl;
return 0;
}
多重背包问题:
无优化
#include<bits/stdc++.h>
using namespace std;
#define ll int // 为了方便修改类型
const ll N=100000;//辅助定义数组
ll m, n; // n是背包容量 m是物品数量
ll v[N], w[N], s[N]; // v是物品的重量 w是物品的价值 s是物品的数量。
ll dp[N], i, j, k; // 辅助计算
int main()
{
//输入顺序按需求更改(不会有人真题都不看就套板子吧?)
cin >> m >> n;
for (i = 1; i <= m; i++)
{
cin >> w[i] >> v[i] >> s[i];
}
//熟悉的流程
for (i = 1; i <= m; i++)
{
for (j = n; j >= v[i]; j--) //倒序是为了防止重复计算
{
for (k = 1; k * v[i] <= j && k <= s[i]; k++)//因为每个物品可以取多次,所以需要循环
{
dp[j] = max(dp[j], dp[j - k * v[i]] + k * w[i]);
}
}
}
//结束了?
cout << dp[n] << endl;
return 0;
//结束了。
}
二进制优化
#include<bits/stdc++.h>
using namespace std;
#define ll int // 为了方便修改类型
const ll N=100000;//辅助定义数组
ll m, n; // n是背包容量 m是物品数量
ll v[N], w[N], s[N]; // v是物品的重量 w是物品的价值 s是物品的数量。
ll dp[N], i, j, k; // 辅助计算
int main()
{
cin >> m >> n;
for (i = 1; i <= m; i++)
{
cin >> v[i] >> w[i] >> s[i];
}
//拆分方式更加优美
for (i = 1; i <= m; i++)
{
for (k = 1; k <= s[i]; k *= 2)
{
for (j = n; j >= k * v[i]; j--)
{
dp[j] = max(dp[j], dp[j - k * v[i]] + k * w[i]);
}
s[i] -= k;
}
for (j = n; j >= s[i] * v[i]; j--)
{
dp[j] = max(dp[j], dp[j - s[i] * v[i]] + s[i] * w[i]);
}
}
//我的回合!输出!
cout << dp[n] << endl;
return 0;
}
混合背包问题
#include<bits/stdc++.h>
using namespace std;
#define ll int // 为了方便修改类型
const ll N=100000;// 辅助定义数组
ll m, n;// n是背包容量 m是物品数量
ll w[N], v[N], s[N];//w物品的价值,v物品的体积,s物品的数量
ll dp[N], i, j, k;//辅助计算
/*多重背包*/
void somebag()
{
for (k = 1; k <= s[i]; k *= 2)
{
for (j = n; j >= k * v[i]; j--)
{
dp[j] = max(dp[j], dp[j - k * v[i]] + k * w[i]);
}
s[i] -= k;
}
for (j = n; j >= s[i] * v[i]; j--)
{
dp[j] = max(dp[j], dp[j - s[i] * v[i]] + s[i] * w[i]);
}
return;
}
/*完全背包*/
void allbag()
{
for (j = 0; j <= n; j++)
{
if (j >= v[i])
{
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
}
}
return;
}
int main(){
cin >> n >> m;
for (i = 1; i <= m; i++)
{
cin >> v[i] >> w[i] >> s[i];
}
for(i=1;i<=m;i++)
{
if(s[i]!=0)
{
somebag(); // 多重背包可以代替01背包
}
else
{
allbag(); // 物品可以无限取,使用完全背包
}
}
cout << dp[n];
return 0;
}