背包问题(改编题,做过的童鞋再回顾一下吧)
说明:
时间限制均为1s,内存限制均为65536
文件名一律是bagx.in/out
整型变量用longint,实型变量用extended就好
背包问题1(bag1)
问题描述
每个物品有一定的体积(废话),但是装入背包的物品的总体积不是一定的。假如每个物品有无限件可用,那么有些体积是永远也装不出来的。为了尽量装满背包,keke要研究一下物品不能装出的最大体积。题目保证有解,如果是是有限解,保证不超过2,000,000,000
如果是无限解,则输出0
输入文件
第一行一个整数n(n<=10),表示物品的件数
第2行到N+1行: 每件物品的体积(1<= <=500)
输出文件
一个整数ans,表示不能用这些物品得到的最大体积。
样例输入
3
3
6
10
样例输出
17
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio>
int n;
int a[510];
int f[100001];
void swap(int &a,int &b){int c=a;a=b;b=c;}
int gcd(int a,int b){
if (a>b) swap(a,b);
if (a==0) return b;
return gcd(b % a,a);
}
int main(){
freopen("bag1.in","r",stdin);
freopen("bag1.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
int t=a[1];
for (int i=2;i<=n;i++){
t=gcd(t,a[i]);
}
if (t!=1){
putchar('0');
putchar('\n');
return 0;
}else{
f[0]=1;
for (int i=1;i<=n;i++){
for (int j=a[i];j<=65536;j++){
f[j] |= f[j-a[i]];
}
}
for (int i=65536;i>=0;i--){
if (!f[i]){
printf("%d\n",i);
return 0;
}
}
printf("0\n");
return 0;
}
}
背包问题2(bag2)
问题描述
Keke来到了超市购物。
每个物品都有价格,正好赶上商店推出促销方案。就是把许多东西一起买更便宜(保证优惠方案一定比原价便宜)。物品要买正好的个数,而且不能为了便宜而买不需要的物品。
给定你优惠方案,和需要购买的物品清单,求出最小的花费。
输入文件
第一行 促销物品的种类数(0 <= s <= 99)。
第二行..第s+1 行 每一行都用几个整数来表示一种促销方式。
第一个整数 n (1 <= n <= 5),表示这种优惠方式由 n 种商品组成。
后面 n 对整数 c 和 k 表示 k (1 <= k <= 5)个编号为 c (1 <= c <= 999)的商品共同构成这种方案。
最后的整数 p 表示这种优惠的优惠价(1 <= p <= 9999)。也就是把当前的方案中的物品全买需要的价格。
第 s+2 行 这行一个整数b (0 <= b <= 5),表示需要购买 b 种不同的商品。
第 s+3 行..第 s+b+2 行 这 b 行中的每一行包括三个整数:c ,k ,和 p 。
C 表示唯一的商品编号(1 <= c
<= 999),
k 表示需要购买的 c 商品的数量(1 <=
k <= 5)。
p 表示 c 商品的原价(1 <=
p <= 999)。
最多购买 5*5=25 个商品。
输出文件
一个整数ans,表示需要花的最小费用
样例输入
2
1 7 3 5
2 7 1 8 2 10
2
7 3 2
8 2 5
样例输出
14
#include <iostream>
#include <cstring>
using namespace std;
struct arr{
int v,k[1002];
}a[102];
struct brr{
int high,buy,p;
}b[7];
int n,m,f[6][6][6][6][6];
void work()
{
memset(f,50,sizeof(f));
f[0][0][0][0][0]=0;
int b1,b2,b3,b4,b5,m1,m2,m3,m4,m5;
for (int i=1;i<=n;i++){
m1=a[i].k[b[1].buy];
m2=a[i].k[b[2].buy];
m3=a[i].k[b[3].buy];
m4=a[i].k[b[4].buy];
m5=a[i].k[b[5].buy];
for (b1=m1;b1<=b[1].high;b1++)
for (b2=m2;b2<=b[2].high;b2++)
for (b3=m3;b3<=b[3].high;b3++)
for (b4=m4;b4<=b[4].high;b4++)
for (b5=m5;b5<=b[5].high;b5++)
f[b1][b2][b3][b4][b5]=min(f[b1][b2][b3][b4][b5],f[b1-m1][b2-m2][b3-m3][b4-m4][b5-m5]+a[i].v);
}
}
int main(){
freopen("bag2.in","r",stdin);
freopen("bag2.out","w",stdout);
int num,l;
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d",&num);
for (int j=1;j<=num;j++){
scanf("%d",&l);
scanf("%d",&a[i].k[l]);
}
scanf("%d",&a[i].v);
}
scanf("%d",&m);
for (int i=1;i<=m;i++){
scanf("%d%d%d",&b[i].buy,&b[i].high,&a[++n].v);
a[n].k[b[i].buy]=1;
}
work();
printf("%d\n",f[b[1].high][b[2].high][b[3].high][b[4].high][b[5].high]);
return 0;
}
背包问题3(bag3)
问题描述
现在又a,b,c三种物品,如果他们安x:y:z混合,就能产生一种神奇的物品d。
当然不一定只产生一份d,但a,b,c的最简比一定是x:y:z
现在给你3种可供选择的物品:
每个物品都是由a,b,c以一定比例组合成的,求出最少的物品数,使得他们能凑出整数个d物品(这里的最少是指三者个数的总和最少)
输入文件
第一行三个整数,表示d的配比(x,y,z)
接下来三行,表示三种物品的配比,每行三个整数(<=10000)。
输出文件
四个整数,分别表示在最少物品总数的前提下d,a,b,c的个数(d是由a,b,c配得的)
目标答案<=10000
如果不存在满足条件的方案,输出NO
样例输入
3 4 5
1 2 3
3 7 1
2 1 2
样例输出
8 1 5 7
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio>
#include <cstring>
#define INF 214748326
double a[10][10];
double b[10][10];
double c[10];
int min=INF;
int ansx,ansy,ansz,ansk;
int trunc(double x){
if ((int)(x+0.5)>(int)x) return (int)x+1;
return (int)x;
}
int main(){
freopen("bag3.in","r",stdin);
freopen("bag3.out","w",stdout);
scanf("%lf%lf%lf",&a[1][4],&a[2][4],&a[3][4]);
scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf",&a[1][1],&a[2][1],&a[3][1],&a[1][2],&a[2][2],&a[3][2],&a[1][3],&a[2][3],&a[3][3]);
memcpy(b,a,sizeof(a));
for (int k=1;k<=10000;k++){
for (int i=1;i<=3;i++) a[i][4]*=k;
for (int i=1;i<3;i++){
for (int j=i+1;j<=3;j++){
double t=1;
if (a[j][i]!=0) t=a[i][i]/a[j][i];
a[j][i]=0;
for (int k=i+1;k<=4;k++){
a[j][k]=t*a[j][k]-a[i][k];
}
}
}
memset(c,0,sizeof(c));
c[3]=a[3][4]/a[3][3];
for (int i=2;i>0;i--){
double tot=0;
for (int j=i+1;j<=3;j++){
tot+=a[i][j]*c[j];
}
c[i]=(a[i][4]-tot)/a[i][i];
}
int x=trunc(c[1]);
int y=trunc(c[2]);
int z=trunc(c[3]);
if (b[1][1]*x+b[1][2]*y+b[1][3]*z==b[1][4]*k
&& b[2][1]*x+b[2][2]*y+b[2][3]*z==b[2][4]*k
&& b[3][1]*x+b[3][2]*y+b[3][3]*z==b[3][4]*k){
if (min>x+y+z){
ansx=x;
ansy=y;
ansz=z;
ansk=k;
min=z+y+z;
}
}
memcpy(a,b,sizeof(a));
}
if (ansx==0 && ansy==0 && ansz==0) printf("NONE");else
printf("%d %d %d %d\n",ansx,ansy,ansz,ansk);
return 0;
}
背包问题4(bag4)
问题描述
为了多买点东西,keke买了好多nike的包,但是每个包的大小不一样。
Keke去超市买了好多零食,每个零食的大小也不一样,现在他要把这些零食都装到包里。
注意,一个零食不能被分成两部分。
给出每个背包和物品的体积,求出做多可将多少物品装入背包中。
输入文件
第一行,一个整数n(1<=n<=50),表示背包的个数
接下来n行,每行一个整数ai表示背包的体积
接下来一行中一个整数m(1<=m<=1024),表示物品的个数
接下来m行,每行一个整数(1<=bi<=128)表示每个物品的体积
输出文件
一个整数,最多能放入背包的物品数。
样例输入
5
5
5
4
3
2
5
1
1
1
1
1
样例输出
5
/*
ID:abccbaz1
LANG:C++
TASK:fence8
*/
#include <cstdio>
#include <cstdlib>
int n,m;
int rail[2000];
int pack[2000];
int sum[2000];
int bag[2000];
int tot;
int res;
int l,r,mid;
int cmp(const void *a,const void *b){
return *(int *)a-*(int *)b;
}
int CMP(const void *a,const void *b){
return *(int *)b-*(int *)a;
}
bool dfs(int d,int a){
if (d==0) return true;
if (res>tot-sum[mid]) return false;
for (int i=a;i<=n;i++){
if (bag[i]>=rail[d]){
bag[i]-=rail[d];
if (bag[i]<rail[1]) res+=bag[i];
if (rail[d]==rail[d-1]){
if (dfs(d-1,i)) return true;
}else if (dfs(d-1,1)) return true;
if (bag[i]<rail[1]) res-=bag[i];
bag[i]+=rail[d];
}
}
return false;
}
int main(){
freopen("bag4.in","r",stdin);
freopen("bag4.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d",&pack[i]);
tot+=pack[i];
}
scanf("%d",&m);
for (int i=1;i<=m;i++){
scanf("%d",&rail[i]);
}
qsort(pack+1,n,sizeof(int),cmp);
qsort(rail+1,m,sizeof(int),cmp);
for (int i=1;i<=m;i++){
sum[i]=sum[i-1]+rail[i];
}
l=0,r=m;
while (sum[r]>tot) r--;
mid=(l + r) >> 1;
while (l<=r){
for (int i=1;i<=n;i++) bag[i]=pack[i];
res=0;
if (dfs(mid,1)){
l=mid+1;
mid=(l + r) >> 1;
}else{
r=mid-1;
mid=(l + r) >> 1;
}
}
int ans=mid;
printf("%d\n",ans);
return 0;
}