1.有一个储蓄罐,告知其空时的重量和当前重量,并给定一些钱币的价值和相应重量
求储蓄罐中最少有多少现金
输入 第一行T 表示后面有T行测试用例
第二行两个数字 空储蓄罐重量 当前储蓄罐重量
第三行一个 整形N 其后有N行,每行有两个数字钱币价值和重量
3
10 110
2
1 1
30 50
10 110
2
1 1
50 30
1 6
2
10 3
20 4
输出
60
100
this is impossible
完全背包特点 每个物品可选数量为无穷,其解法与0-1背包基本一致,不同的仅为状态更新时的顺序
0-1背包之所以逆序是为了保证更新dpj时,dp[j-list[i].w]的状态尚未因本次更新而改变,这是因为0-1
背包至多被选择一次。而完全背包可以选择无限次,那么状态dp[i][j]加号可以由可能已经放入物品i的状态
问用有限的资金最多采购多少公斤粮食
输入 正整数C 表示有C组测试数据 每组测试数据第一行两个整数n和m
分别为经费金额和大米的种类,然后是m行数据,每行包含大米的价格 重量 和对应的袋数
1
8 2
2 100 4
4 100 2
输出 购买大米的最多重量,可以假设经费买不光所有大米,且也可以不用完
400
多重背包 有容积V的背包,给定一些物品,包含体积w 价值v和数量k求背包最大价值量
将原数量为k的物品拆分成若干组,每组物品看作一个物品,其价值和重量为该组中所有
求储蓄罐中最少有多少现金
输入 第一行T 表示后面有T行测试用例
第二行两个数字 空储蓄罐重量 当前储蓄罐重量
第三行一个 整形N 其后有N行,每行有两个数字钱币价值和重量
3
10 110
2
1 1
30 50
10 110
2
1 1
50 30
1 6
2
10 3
20 4
输出
60
100
this is impossible
完全背包特点 每个物品可选数量为无穷,其解法与0-1背包基本一致,不同的仅为状态更新时的顺序
0-1背包之所以逆序是为了保证更新dpj时,dp[j-list[i].w]的状态尚未因本次更新而改变,这是因为0-1
背包至多被选择一次。而完全背包可以选择无限次,那么状态dp[i][j]加号可以由可能已经放入物品i的状态
转移而来,故为顺序
#include<stdio.h>
#define INF 0x7fffffff
int min(int a,int b)
{
return a<b ? a:b;
}
struct E
{
int w;//重量
int v;//价值
} list[501];
int dp[10001];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int s,tmp;
scanf("%d%d",&tmp,&s);//空储蓄罐数量和装满储蓄罐数量
s-=tmp;//计算钱币所占重量
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&list[i].v,&list[i].w);
}
for(int i=0;i<=s;i++)
{
dp[i]=INF;
}
dp[0]=0;
for(int i=1;i<=n;i++)
{//遍历所有物品
for(int j=list[i].w;j<=s;j++)
{//完全背包,顺序遍历所有可能转移状态
if(dp[j-list[i].w]!=INF)
{//若不为无穷,则可以由此状态转移而来
dp[j]=min(dp[j],dp[j-list[i].w]+list[i].v);//取转移最小值
}
}
}
if(dp[s]!=INF)//若存在一种方案使背包恰好装满,输出最小值
printf("%d\n",dp[s]);
else
puts("this is impossible");
}
return 0;
}
2.有资金n元,市场有m种大米,每种大米均为袋装,价格不等,只能整袋购买。
问用有限的资金最多采购多少公斤粮食
输入 正整数C 表示有C组测试数据 每组测试数据第一行两个整数n和m
分别为经费金额和大米的种类,然后是m行数据,每行包含大米的价格 重量 和对应的袋数
1
8 2
2 100 4
4 100 2
输出 购买大米的最多重量,可以假设经费买不光所有大米,且也可以不用完
400
多重背包 有容积V的背包,给定一些物品,包含体积w 价值v和数量k求背包最大价值量
将原数量为k的物品拆分成若干组,每组物品看作一个物品,其价值和重量为该组中所有
物品的价值重量和
#include<stdio.h>
int max(int a,int b)
{
return a>b ? a:b;
}
struct E
{
int w;//价格
int v;//重量
} list[2001];
int dp[101];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int s,n;
scanf("%d%d",&s,&n);
int cnt=0;//拆分后物品总数
for(int i=1;i<=n;i++)
{
int v,w,k;
scanf("%d%d%d",&w,&v,&k);
int c=1;
while(k-c>0)
{//对输入的数字k,差分成1,2,4...k-2^c+1,其中c为使最后一项大于0的整数
k-=c;
list[++cnt].w=c*w;
list[cnt].v=c*v;//拆分后的大米重量和价格均为组成该物品的大米的重量价格和
c*=2;
}
list[++cnt].w=w*k;
list[cnt].v=v*k;
}
for(int i=1;i<=s;i++) dp[i]=0;
for(int i=1;i<=cnt;i++)
{//对拆分后的所有物品进行0-1背包
for(int j=s;j>=list[i].w;j--)
{
dp[j]=max(dp[j],dp[j-list[i].w]+list[i].v);
}
}
printf("%d\n",dp[s]);
}
return 0;
}