背包问题:背包问题详解
一、完全背包问题:疯狂的采药
题目:洛谷P1616
思路:一个经典的完全背包问题,这里用到了降维的思想。
/*完全背包经典问题*/
#include<bits/stdc++.h>
using namespace std;
long long f[100000000],w[10000],v[100000];//f[m]表示在背包重量为m的情况下所取物品的最大价值
int t,m;
int main()
{
cin>>t>>m;
for(int i=1;i<=m;i++)
{
cin>>w[i]>>v[i];
}
for(int i=1;i<=m;i++)
{
for(int j=w[i];j<=t;j++)//这里是从前往后正向推导的
{
f[j]=max(f[j],f[j-w[i]]+v[i]);
}
}
cout<<f[t];
system("pause");
return 0;
}
二、混合背包问题:樱花
题目:洛谷P1833
思路:经典的混合多重背包问题,但这里并没有用到二进制拆分的方法
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 10000010;
const int INF = 100010;
int n, T;
int t[MAXN], c[MAXN], p[MAXN];
int a[MAXN], b[MAXN], f[MAXN];
struct Time {
int h, min;
}s, e;
inline int read() {
int x=0, f=1; char ch=getchar();
while(ch<'0' || ch>'9') {
if(ch == '-') f = -1;
ch = getchar();
}
while(ch>='0' && ch<='9')
x=(x<<3) + (x<<1) + ch-48, ch = getchar();
return x * f;
}//快读函数
int main() {
s.h = read(), s.min = read();
e.h = read(), e.min = read();
n = read();
T = e.min - s.min + (e.h - s.h) * 60;
int cnt = 0;
for(int i=1; i<=n; ++i) {
t[i] = read();
c[i] = read();
p[i] = read();
if(!p[i]) p[i] = INF;
int s = 1;
while(p[i] > s)
{
a[++cnt] = t[i] * s;
b[cnt] = c[i] * s;
p[i] -= s;
s <<= 1;
}
if(p[i])
{
a[++cnt] = t[i] * p[i];
b[cnt] = c[i] * p[i];
}
}
for(int i=1; i<=cnt; ++i)
for(int j=T; j>=a[i]; --j)
{
f[j] = max(f[j], f[j - a[i]] + b[i]);
}
cout<<f[T[;
system("pause")
return 0;
}
三、摆花
题目:洛谷P1077
思路:此题也是经典的动态规划问题,但是只要推到出转移方程后就简单了,同时还要注意没有花盆的情况也算一种。
#include<bits/stdc++.h>
using namespace std;
int f[110][110],a[110],n,m,t;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=0;i<=a[1];i++)f[1][i]=1;//设定边界
for(int i=0;i<=m;i++)f[i][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
t=0;
for(int k=j-a[i];k<=j;k++)
{
if(k>=0){t=(t+f[i-1][k])%1000007;}//状态转移
}
f[i][j]=t;
}
}
cout<<f[n][m];
system("pause")
return 0;
}
四、金明的预算方案
题目:洛谷P1064
思路:本题需要在背包问题的基础上做,可将其转化成01背包。
#include<bits/stdc++.h>
#define maxn 65
using namespace std;
int dp[maxn][32005];
int line[maxn];
int w[maxn];
int v[maxn];
int s[maxn];
int n,m;
int DP(int pos,int rest){
if(pos>=n+1) return 0;
if(dp[pos][rest]!=0)return dp[pos][rest];
if(s[line[pos]]!=0)
{
int ans=DP(pos+1,rest);
if(rest>=v[line[pos]]) ans=max(ans,DP(pos+1,rest-v[line[pos]])+v[line[pos]]*w[line[pos]]);
dp[pos][rest]=ans;
return ans;
}
else
{
int k=pos+1;
while(s[line[k]]!=0)k++;//跳过它的配件
int ans=DP(k,rest);
if(rest>=v[line[pos]]){
ans=max(ans,DP(pos+1,rest-v[line[pos]])+v[line[pos]]*w[line[pos]]);
}
dp[pos][rest]=ans;
return ans;
}
} //直接01背包
bool cmp(const int i,const int j)
{
if((s[i]==0)&&(s[j]==0))
{
return i<j;
}
if(s[i]==0)
{
return i<=s[j];
}
if(s[j]==0)
{
return s[i]<j;
}
else
{
return s[i]<s[j];
} //cmp排序函数,用于实现上文所述的排序
}
int main(){
int z;
freopen("input.txt","r",stdin);
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&v[i],&w[i],&s[i]);
line[i]=i;
}
sort(line+1,line+n+1,cmp);
printf("%d",DP(1,m));
return 0;
}