动态规划的背包问题
P1049 装箱问题 题目链接:https://www.luogu.org/problemnew/show/P1049
题解:01背包裸题
AC代码:
#include <bits/stdc++.h>
using namespace std;
#define _for(i,a,b) for(int i=a;i<=b;i++)
const int maxn = 20007;
int n,m,a[35],dp[maxn];
int main(int argc, char const *argv[])
{
cin>>m>>n;
_for(i,1,n)cin>>a[i];
_for(i,1,n)
{
for(int j = m;j>=a[i];j--)
{
dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
}
}
cout<<m-dp[m]<<endl;
return 0;
}
P1048 采药 题目链接:https://www.luogu.org/problemnew/show/P1048
题解:将时间看作背包容积即可,背包问题
AC代码:
#include <bits/stdc++.h>
using namespace std;
#define _for(i,a,b) for(int i=a;i<=b;i++)
const int maxn = 107;
const int N = 1006;
int n,m,val[maxn],weight[maxn],dp[N];
int main(int argc, char const *argv[])
{
cin>>m>>n;
_for(i,1,n)cin>>weight[i]>>val[i];
_for(i,1,n)
{
for(int j=m;j>=weight[i];j--)
{
dp[j]=max(dp[j],dp[j-weight[i]]+val[i]);
}
}
cout<<dp[m]<<endl;
return 0;
}
P1616 疯狂的采药 题目链接:https://www.luogu.org/problemnew/show/P1616
题解:完全背包问题,将01背包的转换方程反过来写即可。
AC代码
#include <bits/stdc++.h>
using namespace std;
#define _for(i,a,b) for(int i=a;i<=b;i++)
const int maxn = 10007;
const int N = 100006;
int n,m,val[maxn],weight[maxn],dp[N];
int main(int argc, char const *argv[])
{
cin>>m>>n;
_for(i,1,n)cin>>weight[i]>>val[i];
_for(i,1,n)
{
_for(j,weight[i],m)
{
dp[j]=max(dp[j],dp[j-weight[i]]+val[i]);
}
}
cout<<dp[m]<<endl;
return 0;
}
P1064 金明的预算方案 题目链接:https://www.luogu.org/problemnew/show/P1064
题解:重要度*价格就是价值,因为最多两个附件,所以在原本的转移方程上多出了三个选择,分别是选择第一 个附件,选择第二个附件,或者附件都选,那么加三个转移方程即可。
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 66;
const int N = 32006;
#define _for(i,a,b) for(int i=a;i<=b;i++)
int n,m,main_val[maxn],main_weight[maxn],dp[N],vis[maxn],val[maxn][3],weight[maxn][3];
int main(int argc, char const *argv[])
{
cin>>m>>n;
_for(i,1,n)
{
int x,y,z;
cin>>main_weight[i]>>y>>z;
if(z==0)main_val[i]=main_weight[i]*y;
else if(weight[z][0]!=0)
{
weight[z][1]=main_weight[i];
val[z][1]=main_weight[i]*y;
}
else
{
weight[z][0]=main_weight[i];
val[z][0]=main_weight[i]*y;
}
}
_for(i,1,n)
{
for(int j=m;j>=main_weight[i];j--)
{
dp[j]=max(dp[j],dp[j-main_weight[i]]+main_val[i]);
if(j>=main_weight[i]+weight[i][0])
{
dp[j]=max(dp[j],dp[j-main_weight[i]-weight[i][0]]+val[i][0]+main_val[i]);
}
if(j>=main_weight[i]+weight[i][1])
{
dp[j]=max(dp[j],dp[j-main_weight[i]-weight[i][1]]+val[i][1]+main_val[i]);
}
if(j>=main_weight[i]+weight[i][0]+weight[i][1])
{
dp[j]=max(dp[j],dp[j-main_weight[i]-weight[i][0]-weight[i][1]]+val[i][0]+main_val[i]+val[i][1]);
}
}
}
cout<<dp[m]<<endl;
return 0;
}
P1164 小A点菜 题目链接:https://www.luogu.org/problemnew/show/P1164
题解:设dp[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];
AC代码:
/*
* @Author: 王文宇
* @Date: 2018-03-02 14:38:17
* @Last Modified by: 王文宇
* @Last Modified time: 2018-03-06 12:57:37
*/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 107;
const int N = 10006;
#define _for(i,a,b) for(int i=a;i<=b;i++)
int n,m,dp[maxn][N],a[maxn];
int main(int argc, char const *argv[])
{
cin>>n>>m;
_for(i,1,n)cin>>a[i];
_for(i,1,n)
{
_for(j,1,m)
{
if(a[i]==j)dp[i][j]=dp[i-1][j]+1;
else if(a[i]>j)dp[i][j]=dp[i-1][j];
else dp[i][j]=dp[i-1][j]+dp[i-1][j-a[i]];
}
}
cout<<dp[n][m]<<endl;
return 0;
}