题目链接:https://acm.zcmu.edu.cn/JudgeOnline/problem.php?id=1381
题目大意
n种砝码,每种砝码重ai,有bi个,问你最小不能称的重量是多大?最大不超过8500.
范围:(a<100,b<100)
思路
背包题,有数量限制,那么就是多重背包,就是看背包能不能装满,以下两种dp方式求解01背包。
1.dp[i]表示容量为i的包能不能装满,能的话dp[i]=1。
2.dp[i]表示容量为i的包能装的最大价值,其中每个砝码的价值等于重量本身,
最后从1开始往上累加,找到第一个dp为0的,这个就是最小的不能称出的重量。
ac代码
解法1:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e4 + 5;
int dp[maxn], s; //dp[i]表示容量为i的包能否装满, s是最大容量
void bag1(int w){ //01背包
for(int i = s; i >= w; i --)
if(dp[i - w]) dp[i] = 1; //i-w能装满的话,加上此时的w,那么也能装满i
}
void bag3(int w, int num){ //多重背包
int k = 1;
while(k <= num){
bag1(w * k); //分成多个01背包
num -= k;
k <<= 1;
}
bag1(w * num);
}
int weight[maxn], num[maxn]; //weight表示砝码重量,num表示砝码数量
int main(){
int n;
while(~scanf("%d", &n)){
if(n == 0) break;
s = 0;
memset(dp, 0, sizeof(dp));
dp[0] = 1; //容量为0的包肯定装得满,本身就算满
for(int i = 1; i <= n; i ++){
scanf("%d%d", &weight[i], &num[i]);
s += weight[i] * num[i];
}
for(int i = 1; i <= n; i ++){
bag3(weight[i], num[i]); //多重背包
}
int id = 1;
while(dp[id]) id ++; //dp[id]==1说明装满了
printf("%d\n", id);
}
return 0;
}
解法2:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e5 + 5;
int dp[maxn], s; //dp[i]表示容量为i的包能获得最大价值,s是最大容量
void bag1(int w, int v){ //01背包
for(int i = s; i >= w; i --)
dp[i] = max(dp[i], dp[i - w] + v);
}
void bag3(int w, int v, int num){ //多重背包
int k = 1;
while(k <= num){
bag1(w * k, v * k);
num -= k;
k <<= 1;
}
bag1(w * num, v * num);
}
int weight[maxn], num[maxn];
int main(){
int n;
while(~scanf("%d", &n)){
if(n == 0) break;
s = 0;
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; i ++){
scanf("%d%d", &weight[i], &num[i]);
s += weight[i] * num[i];
}
for(int i = 1; i <= n; i ++){
bag3(weight[i], weight[i], num[i]); //价值就是重量本身
}
int id = 1;
while(dp[id] == id) id ++; //最大价值等于重量说明装满了
printf("%d\n", id);
}
return 0;
}