基础背包问题的一些题目!!
2014-01-19 17:59
387 查看
hdu1203
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1203
每件物品的cos为a[i],价值与b[i]有关,是一个简单的01背包问题。
AC代码:
hdu2602
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=2602
典型的01背包,直接见代码:
hdu 1171
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1171
有n件物品,每件物品的价值和数量不同,是一个完全背包问题,由于数量并不是很大,可以将它转换为01背包问题。
AC代码:
hdu1864
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1864
貌似是个背包问题,不过背包需要用到int,由于答案需要保留两位有效数字,所以将背包的cos放大100倍,把背包的容量也扩大一百倍,不过这样多少会有点精度的损失。01背包。
hdu1712
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1712
题目说的意思是有n个作业,如果用j天去完成第i项作业,那么会得到价值wei[i][j],因此每项任务要么不完成,要么只能完成一次,是一个完全背包的问题,可以先看下背包九讲的内容P06.
for 所有的组k
for v=V..0
for 所有的i属于组k
f[v]=max{f[v],f[v-c[i]]+w[i]}
意思就是说每个组里面最多只能选一项。
AC代码:
hdu2660
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=2660
题目先给你一个n,k,有n个物品,下面依次是n个物品的cos和wei,然后是背包的容量是vol,不过有个条件背包装的物品数目得不多于k,因此需要用到二维的01背包。dp[l][j]表示容量为l,最多装j个物品时候装得最大价值。状态转移方程为 dp[l][j]=max(dp[l][j],dp[l-cos[i]][j-1]+wei[i])
AC代码:
hdu1709
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1709
题目大意:给定几个数字,作为砝码,看哪些不能被称出。
解题思路:先01背包求出可以相加的所有的情况,找出可以被称出的重量,再暴力找出可以使用减法的情况。
AC代码:
poj3624
题目地址:http://poj.org/problem?id=3624
标准的01背包。。。
白天断电断网,一血也没了。。
AC代码:
hdu 2159
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=2159
题目大意:中文题目,就不做解释了,是一个二维完全背包的标准题目。
AC代码:
hdu 2844&&poj 1742
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=2844
多重背包,题目意思,是给n种金币的金额,金额不能超过m,然后输入每种金币的v[i],c[i]分别代表这种金币代表的金额和这种金币的数量。需要输出这些金币组合能达到不超过m的金额是多少种。
典型的二维多重背包题目。
如果采取普通的多重背包的解法,那么是O(n*m*c)
n是物品的种类数目,m是背包的容量,c是物品的每种种类相应的数目
如果应用这个题目,那么是10^7*10^3=10^10的时间复杂度,当然不可行。
当然我们可以将复杂度降到O(n*m),不过我们需要多开一个数组记录每次用物品的个数
这个题目需要求解的是能组成多少<=m的总量。
具体见代码。
hdu 2191
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=2191
题目大意:给你背包的容量vol,然后给你n种物品,每种物品有它的价值,体积,当然还有每种物品的数量。典型的多重背包,由于种类最多为100,每种物品数量最多为20,如果转换为01背包总量最多为2*10^3然后再乘上背包容量100,10^5的时间复杂度,可以接受。
AC代码:
poj 2392 完全背包
题目地址:http://poj.org/problem?id=2392
题目大意:给你k种石头,每种石头有自己的高度h,和最高能呆的高度a,还有数量c,问用这些石头堆起来最高的高度。
我们需要对这些石头的最高能呆的高度从低到高排个序,然后就直接用完全背包的套路就可以了。
例如
2
8 15 1
3 8 3
排序之后最大高度是14,不排序的最大高度是8.
AC代码:
poj 2184经典的01背包
题目地址:http://poj.org/problem?id=2184
题目的意思是给你一些牛的s值和f值,让你在这些牛选取一些牛使得在保证s值之和>=0,f值之和>=0的基础上使得所有的s值和f值之和最大。
首先看到这个题目就会想到背包,而且是01背包,但是中间有负数,处理的方法就是采取手动的移位,所有的都往右移动即可。我们所要做的就是用dp[s]背包来背f,就是s一定的情况下使得f最大,当然我们也需要记得01背包循环的顺序,所以需要根据s[i]的正负值分类考虑循环顺序。详见代码:
AC代码:
#include<iostream>
#include<cstdio>
using namespace std;
const int tab=1e5;
int s[105],f[105];
int dp[200005];
int main()
{
int n,i,j;
while(cin>>n)
{
for(i=0;i<n;i++)
cin>>s[i]>>f[i];
for(i=0;i<=2e5;i++)
dp[i]=-1e8;
dp[tab]=0;
int l=0,r=0;
for(i=0;i<n;i++)
{
l=min(l,l+s[i]);
r=max(r,r+s[i]);
if(s[i]<0)
{
for(j=l;j<=r;j++)
{
dp[j+tab]=max(dp[j+tab-s[i]]+f[i],dp[j+tab]);
}
}
else
{
for(j=r;j>=l;j--)
{
dp[j+tab]=max(dp[j+tab-s[i]]+f[i],dp[j+tab]);
}
}
}
int res=0;
for(i=0;i<=r;i++)
{
if(dp[i+tab]>=0)
res=max(res,i+dp[i+tab]);
}
cout<<res<<endl;
}
return 0;
}
/*
5
-5 7
8 -6
6 -3
2 1
-8 -5
*/
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1203
每件物品的cos为a[i],价值与b[i]有关,是一个简单的01背包问题。
AC代码:
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> using namespace std; double dp[10005]; int a[10005]; double b[10005]; int main() { int n,m,i,j; while(cin>>n>>m&&n+m) { for(i=0;i<m;i++) cin>>a[i]>>b[i]; memset(dp,0,sizeof(dp)); for(i=0;i<m;i++) for(j=n;j>=a[i];j--) dp[j]=max(dp[j],1-(1-dp[j-a[i]])*(1-b[i])); double res=dp *100; printf("%.1f%%\n",res); } return 0; }
hdu2602
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=2602
典型的01背包,直接见代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int dp[1002],i,j,num,vol; int cos[1002],wei[1002]; void ZeroOnePack(int cost,int weight) { for(j=vol;j>=cost;j--) if(dp[j]<dp[j-cost]+weight) dp[j]=dp[j-cost]+weight; } int main() { int tes,n; cin>>tes; while(tes--) { cin>>n>>vol; for(i=0;i<n;i++) scanf("%d",&cos[i]); for(i=0;i<n;i++) scanf("%d",&wei[i]); memset(dp,0,sizeof(dp)); for(i=0;i<n;i++) ZeroOnePack(wei[i],cos[i]); cout<<dp[vol]<<endl; } return 0; }
hdu 1171
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1171
有n件物品,每件物品的价值和数量不同,是一个完全背包问题,由于数量并不是很大,可以将它转换为01背包问题。
AC代码:
//用两个包使得装得总量差尽量小 //就找一个总量sum/2的包看最多能装多少 //物品最多有n*m<=5000个.箱子开5000*50/2<2*10^5 #include<iostream> #include<cstdio> #include<cstring> using namespace std; int dp[200005]; int wei[5005]; int main() { int t,i,j,n,v,m,sum; while(cin>>t&&t>0) { n=sum=0; memset(dp,0,sizeof(dp)); for(i=0;i<t;i++) { cin>>v>>m; sum+=v*m; while(m--) wei[n++]=v; } for(i=0;i<n;i++) for(j=sum/2;j>=wei[i];j--) dp[j]=max(dp[j],dp[j-wei[i]]+wei[i]); cout<<sum-dp[sum/2]<<" "<<dp[sum/2]<<endl; } return 0; }
hdu1864
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1864
貌似是个背包问题,不过背包需要用到int,由于答案需要保留两位有效数字,所以将背包的cos放大100倍,把背包的容量也扩大一百倍,不过这样多少会有点精度的损失。01背包。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; double wei[35],dp[3000005]; int main() { double sum,sa,sb,sc,money; int t,n,q,i,j; int flag; char c; while(cin>>sum>>t&&t) { n=0; memset(dp,0,sizeof(dp)); while(t--) { cin>>q; sa=sb=sc=0; //分别记录每张发票的A,B,C价钱 flag=0; while(q--) { scanf(" %c:%lf",&c,&money); if(c<'A'||c>'C'||money>600) //不可报销或单项物品金额>600 flag=1; if(c=='A') sa+=money; else if(c=='B') sb+=money; else if(c=='C') sc+=money; } if(!flag&&sa+sb+sc<=1000&&sa<=600&&sb<=600&&sc<=600) wei[n++]=sa+sb+sc; } int isum=sum*100; for(i=0;i<n;i++) { int iwei=wei[i]*100; for(j=isum;j>=iwei;j--) //同时扩大100倍 dp[j]=max(dp[j],dp[j-iwei]+wei[i]); } printf("%.2lf\n",dp[isum]); } return 0; } /* 200.00 3 2 A:23.50 B:100.00 1 C:650.00 3 A:59.99 A:120.00 X:10.00 1200.00 2 2 B:600.00 A:400.00 1 C:200.50 1200.50 3 2 B:600.00 A:400.00 1 C:200.50 1 A:100.00 100.00 0 1000 4 1 A:300 1 B:300 1 A:200 1 C:500 */
hdu1712
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1712
题目说的意思是有n个作业,如果用j天去完成第i项作业,那么会得到价值wei[i][j],因此每项任务要么不完成,要么只能完成一次,是一个完全背包的问题,可以先看下背包九讲的内容P06.
for 所有的组k
for v=V..0
for 所有的i属于组k
f[v]=max{f[v],f[v-c[i]]+w[i]}
意思就是说每个组里面最多只能选一项。
AC代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int wei[105][105]; int dp[105]; int main() { int n,m,i,j,k; while(cin>>n>>m&&n+m) { memset(dp,0,sizeof(dp)); for(i=1;i<=n;i++) for(j=1;j<=m;j++) scanf("%d",&wei[i][j]); for(i=1;i<=n;i++) //分成的n组 for(j=m;j>=0;j--) //总共用j天 for(k=1;k<=m;k++) //所有的k属于组i if(j>=k) dp[j]=max(dp[j],dp[j-k]+wei[i][k]); cout<<dp[m]<<endl; } return 0; }
hdu2660
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=2660
题目先给你一个n,k,有n个物品,下面依次是n个物品的cos和wei,然后是背包的容量是vol,不过有个条件背包装的物品数目得不多于k,因此需要用到二维的01背包。dp[l][j]表示容量为l,最多装j个物品时候装得最大价值。状态转移方程为 dp[l][j]=max(dp[l][j],dp[l-cos[i]][j-1]+wei[i])
AC代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int dp[1002][21],i,j,vol,k,l; int cos[1002],wei[1002]; int main() { int T; cin>>T; while(T--) { memset(dp,0,sizeof(dp)); int n; scanf("%d%d",&n,&k); for(i=0;i<n;i++) scanf("%d%d",&wei[i],&cos[i]); scanf("%d",&vol); for(i=0;i<n;i++) for(l=vol;l>=cos[i];l--) for(j=1;j<=k;j++) dp[l][j]=max(dp[l][j],dp[l-cos[i]][j-1]+wei[i]); printf("%d\n",dp[vol][k]); } return 0; }
hdu1709
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1709
题目大意:给定几个数字,作为砝码,看哪些不能被称出。
解题思路:先01背包求出可以相加的所有的情况,找出可以被称出的重量,再暴力找出可以使用减法的情况。
AC代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int dp[10005]; int vis[10005]; int xx[10005]; int res[10005]; int a[105],sum,n,t; void onepack(int cost,int weight) { int l; for(l=sum;l>=cost;l--) if(dp[l]<dp[l-cost]+weight) dp[l]=dp[l-cost]+weight; } int main() { int i,j; while(~scanf("%d",&n)) { memset(dp,0,sizeof(dp)); memset(vis,0,sizeof(vis)); sum=0; for(i=0;i<n;i++) { scanf("%d",&a[i]); sum+=a[i]; } for(i=0;i<n;i++) onepack(a[i],a[i]); for(i=1;i<=sum;i++) vis[dp[i]]=1; //先背包求出所有和能组成的 t=0; for(i=1;i<=sum;i++) if(vis[i]) xx[t++]=i; //把背包求出的可行值都存放入xx数组中 for(i=0;i<t;i++) for(j=i+1;j<t;j++) vis[xx[j]-xx[i]]=1; //用一次减法可以求出的 t=0; for(i=1;i<=sum;i++) if(!vis[i]) res[t++]=i; printf("%d\n",t); if(t>0) { for(i=0;i<t-1;i++) printf("%d ",res[i]); printf("%d\n",res[t-1]); } } return 0; }
poj3624
题目地址:http://poj.org/problem?id=3624
标准的01背包。。。
白天断电断网,一血也没了。。
AC代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int dp[15000]; int cos[5000],wei[5000]; int main() { int i,j,n,vol; while(cin>>n>>vol) { memset(dp,0,sizeof(dp)); for(i=0;i<n;i++) cin>>cos[i]>>wei[i]; for(i=0;i<n;i++) for(j=vol;j>=cos[i];j--) dp[j]=max(dp[j],dp[j-cos[i]]+wei[i]); cout<<dp[vol]<<endl; } return 0; }
hdu 2159
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=2159
题目大意:中文题目,就不做解释了,是一个二维完全背包的标准题目。
AC代码:
#include<iostream> #include<cstring> #include<cstdio> using namespace std; int dp[105][105]; int wei[105],cos[105]; int main() { int i,j,k; int n,m,K,s; while(cin>>n>>m>>K>>s) { for(i=0;i<K;i++) scanf("%d%d",&wei[i],&cos[i]); memset(dp,0,sizeof(dp)); for(i=0;i<K;i++) { for(j=1;j<=m;j++) { for(k=1;k<=s;k++) { if(j>=cos[i]) dp[j][k]=max(dp[j][k],dp[j-cos[i]][k-1]+wei[i]); } } } if(dp[m][s]<n) { puts("-1"); continue; } int res=m; for(i=1;i<=m;i++) for(j=1;j<=s;j++) { if(dp[i][j]>=n) res=min(res,i); } res=m-res; cout<<res<<endl; } return 0; } /* 10 10 1 10 1 1 10 10 1 9 1 1 9 10 2 10 1 1 2 2 */
hdu 2844&&poj 1742
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=2844
多重背包,题目意思,是给n种金币的金额,金额不能超过m,然后输入每种金币的v[i],c[i]分别代表这种金币代表的金额和这种金币的数量。需要输出这些金币组合能达到不超过m的金额是多少种。
典型的二维多重背包题目。
如果采取普通的多重背包的解法,那么是O(n*m*c)
n是物品的种类数目,m是背包的容量,c是物品的每种种类相应的数目
如果应用这个题目,那么是10^7*10^3=10^10的时间复杂度,当然不可行。
当然我们可以将复杂度降到O(n*m),不过我们需要多开一个数组记录每次用物品的个数
这个题目需要求解的是能组成多少<=m的总量。
具体见代码。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=100005; int visi[maxn]; int used[maxn]; int v[105],c[105]; int main() { int n,m; int i,j; while(cin>>n>>m&&n+m) { for(i=0;i<n;i++) cin>>v[i]; for(i=0;i<n;i++) cin>>c[i]; int res=0; memset(visi,0,sizeof(visi)); visi[0]=1; for(i=0;i<n;i++) { memset(used,0,sizeof(used)); for(j=v[i];j<=m;j++) { if(!visi[j]&&visi[j-v[i]]&&used[j-v[i]]<c[i]) { visi[j]=1; used[j]=used[j-v[i]]+1; res++; } } } cout<<res<<endl; } return 0; } /* 3 10 1 2 4 2 1 1 2 5 1 4 2 1 0 0 */
hdu 2191
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=2191
题目大意:给你背包的容量vol,然后给你n种物品,每种物品有它的价值,体积,当然还有每种物品的数量。典型的多重背包,由于种类最多为100,每种物品数量最多为20,如果转换为01背包总量最多为2*10^3然后再乘上背包容量100,10^5的时间复杂度,可以接受。
AC代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int cos[2005],wei[2005]; int dp[105]; int main() { int tes; cin>>tes; int i,j; while(tes--) { int vol,m; cin>>vol>>m; int num=0; int a,b,c; for(i=0;i<m;i++) { cin>>a>>b>>c; for(j=0;j<c;j++) //多重背包转换为01背包 { cos[num]=a; wei[num++]=b; } } memset(dp,0,sizeof(dp)); for(i=0;i<num;i++) for(j=vol;j>=cos[i];j--) dp[j]=max(dp[j],dp[j-cos[i]]+wei[i]); cout<<dp[vol]<<endl; } return 0; } /* 1 8 2 2 100 4 4 100 2 */
poj 2392 完全背包
题目地址:http://poj.org/problem?id=2392
题目大意:给你k种石头,每种石头有自己的高度h,和最高能呆的高度a,还有数量c,问用这些石头堆起来最高的高度。
我们需要对这些石头的最高能呆的高度从低到高排个序,然后就直接用完全背包的套路就可以了。
例如
2
8 15 1
3 8 3
排序之后最大高度是14,不排序的最大高度是8.
AC代码:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> using namespace std; int dp[40005]; int num[40005]; struct node { int h; int a; int c; }block[405]; bool cmp(node p1,node p2) { return p1.a<p2.a; } int main() { int k,i,j; while(cin>>k) { memset(dp,0,sizeof(dp)); dp[0]=1; for(i=0;i<k;i++) cin>>block[i].h>>block[i].a>>block[i].c; sort(block,block+k,cmp); int ans=0; for(i=0;i<k;i++) { memset(num,0,sizeof(num)); //记录用了多少个石头的 for(j=block[i].h;j<=block[i].a;j++) { if(!dp[j]&&dp[j-block[i].h]&&num[j-block[i].h]<block[i].c) { dp[j]=1; num[j]=num[j-block[i].h]+1; ans=max(ans,j); } } } cout<<ans<<endl; } return 0; }
poj 2184经典的01背包
题目地址:http://poj.org/problem?id=2184
题目的意思是给你一些牛的s值和f值,让你在这些牛选取一些牛使得在保证s值之和>=0,f值之和>=0的基础上使得所有的s值和f值之和最大。
首先看到这个题目就会想到背包,而且是01背包,但是中间有负数,处理的方法就是采取手动的移位,所有的都往右移动即可。我们所要做的就是用dp[s]背包来背f,就是s一定的情况下使得f最大,当然我们也需要记得01背包循环的顺序,所以需要根据s[i]的正负值分类考虑循环顺序。详见代码:
AC代码:
#include<iostream>
#include<cstdio>
using namespace std;
const int tab=1e5;
int s[105],f[105];
int dp[200005];
int main()
{
int n,i,j;
while(cin>>n)
{
for(i=0;i<n;i++)
cin>>s[i]>>f[i];
for(i=0;i<=2e5;i++)
dp[i]=-1e8;
dp[tab]=0;
int l=0,r=0;
for(i=0;i<n;i++)
{
l=min(l,l+s[i]);
r=max(r,r+s[i]);
if(s[i]<0)
{
for(j=l;j<=r;j++)
{
dp[j+tab]=max(dp[j+tab-s[i]]+f[i],dp[j+tab]);
}
}
else
{
for(j=r;j>=l;j--)
{
dp[j+tab]=max(dp[j+tab-s[i]]+f[i],dp[j+tab]);
}
}
}
int res=0;
for(i=0;i<=r;i++)
{
if(dp[i+tab]>=0)
res=max(res,i+dp[i+tab]);
}
cout<<res<<endl;
}
return 0;
}
/*
5
-5 7
8 -6
6 -3
2 1
-8 -5
*/
相关文章推荐
- [面试题目]IT面试中的一些基础问题
- Java对象基础的一些小问题
- 小班讲课之动态规划基础背包问题
- 信息安全基础虚拟机实验的一些问题及解决(win2003)
- 【算法系列学习】[kuangbin带你飞]专题十二 基础DP1 F - Piggy-Bank 【完全背包问题】
- 关于一些基础的Java问题的解答(四)
- 0-1背包问题入门小结 动态规划(DP)经典题目 POJ324 POJ1276
- 谈谈一些有趣的CSS题目(七)-- 消失的边界线问题
- dp入门与两个基础的背包问题
- cordova入门基础教程及使用中遇到的一些问题总结
- 一些基础的java问题及一道简单的java题和我的回答
- 背包基础问题
- 关于java的一些问题,比较基础,大家可以看看咯
- java一些基础问题(听说是java应聘者老被问的问题!)
- 母函数的一些问题:Ignatius and the Princess III&&Square Coins&&选课时间(题目已修改,注意读题)&&Holding Bin-Laden Captive!
- DMA的一些基础问题
- c#与wpf的一些基础语法问题(摘用)
- 一些项目——背包问题
- 关于一些基础的Java问题的解答(四)
- 最近做的一些比较基础的笔试面试题目