背包问题总结篇
Posted MissZhou要努力
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了背包问题总结篇相关的知识,希望对你有一定的参考价值。
1.混合了贪心思想的背包入门
nefu1028暑假计划 01背包
给定工作开始时间、完成时间、给的工资,工作不能重叠,求最大收益。
一维Dp表示截止到当前时间的最大收益,但是事先要对结构体按结束时间排序,防止前一状态没有值
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[1005];
struct money
{
int l,r,w;
}a[1005];
int cmp(money x,money y)//排序都快忘了怎么写了= =
{
if(x.r==y.r) return x.l<y.l;
return x.r<y.r;
}
int main()
{
// freopen("cin.txt","r",stdin);
int n,t,m;
scanf("%d",&t);
while(t--)
{
memset(dp,0,sizeof(dp));
scanf("%d%d",&m,&n);//假期时间m和可做的工作数n
for(int i=1;i<=n;i++) scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].w);
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++)
{
for(int j=m;j>=a[i].r;j--)
{
dp[j]=max(dp[j],dp[j]-(dp[a[i].r]-dp[a[i].l-1])+a[i].w);//重点的重点
}
}
printf("%d\\n",dp[m]);
}
}
2.凑一半 裸的背包
UVA 562 Dividing coins 01背包
#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
using namespace std;
int price[50500],f[50500],n,t,sum;
int dp()
{
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++)
{
for(int j=sum;j>=price[i];j--)
{
if(f[j]<f[j-price[i]]+price[i])
f[j]=f[j-price[i]]+price[i];
}
}
return f[sum];
}
int main()
{
// freopen("cin.txt","r",stdin);
while(~scanf("%d",&t))
{
while(t--)
{
scanf("%d",&n);
sum=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&price[i]);
sum+=price[i];
}
int cnt=sum;
sum=(sum+1)/2;
cnt=dp()*2-cnt;
if(cnt<0) cnt=-cnt;
printf("%d\\n",cnt);
}
}
return 0;
}
3.概率不超过某值的最大收益
hdu2955 Robberies 01背包的变形
加法变成乘法而已
#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
double pj[1050],dp[100500],p,rate;
int t,m[1050],n,sum;
double max(double a,double b)
{
if(a<b) return b;
else return a;
}
int main()
{
// freopen("cin.txt","r",stdin);
while(~scanf("%d",&t))
{
while(t--)
{
memset(dp,0,sizeof(dp));
dp[0]=1;
sum=0;
scanf("%lf%d",&p,&n);
p=1-p;
for(int i=0;i<n;i++)
{
scanf("%d%lf",&m[i],&pj[i]);
pj[i]=1-pj[i];
sum+=m[i];
}
for(int i=0;i<n;i++)
{
for(int j=sum;j>=m[i];j--)
dp[j]=max(dp[j],dp[j-m[i]]*pj[i]);
}
for(int i=sum;i>=0;i--)
{
if(dp[i]>p)
{
printf("%d\\n",i);
break;
}
}
}
}
return 0;
}
4."混合背包"
2015多校联合第十场hdu5410CRB and His Birthday 01背包+完全背包
完全背包中若选择某种物品选一次加一个a[i],另加b[i]的价值,只加一次。在第二层for循环中先进行一次01背包算b[i]+a[i],再进行一次多重背包算a[i]
#include <iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int dp[2005],cost[2005],a[2005],b[2005];
int main()
{
//freopen("cin.txt","r",stdin);
int t,m,n;
while(cin>>t)
{
while(t--)
{
cin>>m>>n;
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++) cin>>cost[i]>>a[i]>>b[i];
for(int i=0;i<n;i++)
{
for(int j=m;j>=cost[i];j--)
if(dp[j]<dp[j-cost[i]]+a[i]+b[i]) dp[j]=dp[j-cost[i]]+a[i]+b[i];
for(int j=cost[i];j<=m;j++)
if(dp[j]<dp[j-cost[i]]+a[i]) dp[j]=dp[j-cost[i]]+a[i];
}
cout<<dp[m]<<endl;
}
}
return 0;
}
5.01背包入门题
0-1背包:nefu19采药hdu2546饭卡
#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int n;
int price[1005],f[1005];
int m;
int main()
{
//freopen("data.in.txt","r",stdin);
while(~scanf("%d",&n)&&n)
{
for(int i=1;i<=n;i++) scanf("%d",&price[i]);
scanf("%d",&m);
f[0]=0;
//for(int i=1;i<=n;i++) f[i]=-999999;
memset(f,0,sizeof(f));
sort(price+1,price+n+1);
for(int i=1;i<=n-1;i++)
{
for(int v=m-5;v>=price[i];v--)
f[v]=max(f[v],f[v-price[i]]+price[i]);
}
if(m>=5) printf("%d\\n",m-f[m-5]-price[n]);
else printf("%d\\n",m);
}
return 0;
}
#include <iostream>
#include<cstdio>
#include<cstring>
//#define INF 0x7ffffff
using namespace std;
int cost[1005];
int price[1005];
int f[1005];
int main()
{
int m,t;
while(~scanf("%d%d",&t,&m))
{
f[0]=0;
memset(f,0,sizeof(f));
//for(int i=1;i<=m;i++) f[i]=-999999;
for(int i=1;i<=m;i++) scanf("%d%d",&cost[i],&price[i]);
for(int i=1;i<=m;i++)
{
for(int v=t;v>=cost[i];v--)
f[v]=max(f[v],f[v-cost[i]]+price[i]);
}
printf("%d\\n",f[t]);
}
return 0;
}
6.同第二题 凑一半
hdu1171big events in hdu【多重背包模板】
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[50005];
int value[60],num[60];
int n,total,sum;
void zero(int cost,int weight)
{
for(int i=total;i>=cost;i--) dp[i]=max(dp[i],dp[i-cost]+weight);
}
void complete(int cost,int weight)
{
for(int i=cost;i<=cost;i++) dp[i]=max(dp[i],dp[i-cost]+weight);
}
void multi(int cost,int weight,int cnt)
{
if(total<=cnt*cost)
{
complete(cost,weight);
return;
}
int k=1;
while(k<=cnt)
{
zero(k*cnt,k*weight);
cnt=cnt-k;
k=2*k;
}
zero(cnt*cost,cnt*weight);
}
int main()
{
while(~scanf("%d",&n))
{
if(n==-1) break;
total=0;
sum=0;
for(int i=0;i<n;i++) {
scanf("%d%d",&value[i],&num[i]);
total+=(value[i]*num[i]);
}
printf("%d \\n",total);
sum=total;
total/=2;
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
{
multi(value[i],value[i],num[i]);
}
printf("%d %d\\n",sum-dp[total],dp[total]);
}
return 0;
}
也可以用01背包搞 就是把相同价值的一种看成是多件
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,tot,a,b,sum;
int dp[255000],val[600];
int main()
{
while(~scanf("%d",&n),n>0)
{
sum=0;
tot=0;
for(int i=0;i<n;i++)
{
scanf("%d%d",&a,&b);
while(b--)
{
val[tot++]=a;
sum+=a;
}
}
memset(dp,0,sizeof(dp));
for(int i=0;i<tot;i++)
{
for(int j=sum/2;j>=val[i];j--)
{
dp[j]=max(dp[j],dp[j-val[i]]+val[i]);
}
}
printf("%d %d\\n",sum-dp[sum/2],dp[sum/2]);
}
return 0;
}
7. 01背包求第k优解
hdu2639bone collector II【第K优解】
作为一个正常的背包,我们必须做的两重循环是一定要写的,接下来就是维护最优解到第k优解的的数组。个人觉得这个题最最值得学习的就是维护数组的写法:
首先每次想加入新物品的时候,正常来说我们有两个值:之前的dp和加入新物品时的值,然而我们现在也需要考虑第k优解的问题,所以用两个临时的数组倒一下,再用这两个数组合并到一起存储到最终的dp数组中
/************
hdu2639
2015.10.20
109MS 5548K 1226B
************/
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[1009][1009];
int value[109],cost[109];
int n,k,v,t;
int a[1009],b[1009];
int main()
{
while(~scanf("%d",&t))
{
while(t--)
{
scanf("%d%d%d",&n,&v,&k);
for(int i=1;i<=n;i++) scanf("%d",&value[i]);
for(int i=1;i<=n;i++) scanf("%d",&cost[i]);
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
for(int j=v;j>=cost[i];j--)
{
for(int m=1;m<=k;m++)
{
a[m]=dp[j][m];
b[m]=dp[j-cost[i]][m]+value[i];
}
int x=1,y=1,w=1;
a[k+1]=-1;b[k+1]=-1;
while((w<=k)&&(x<=k||y<=k))
{
if(a[x]<b[y]) dp[j][w]=b[y++];
else dp[j][w]=a[x++];
if(w==1||dp[j][w-1]!=dp[j][w]) w++;
}
}
printf("%d\\n",dp[v][k]);
}
}
return 0;
}
8.
hdu3466Proud Merchants【至少需要Qi才能买Pi】
hdu5188zhx and contest [01背包至少li才能。。。]
以上是关于背包问题总结篇的主要内容,如果未能解决你的问题,请参考以下文章