タイトルリンク:https://acm.zcmu.edu.cn/JudgeOnline/problem.php?id = 1381
トピック
重りはn種類あり、それぞれai、biありますが、重さを測ることができない最小の重りは何ですか?最大値は8500を超えません。
範囲:(a <100、b <100)
アイデア
バックパックの問題、数に制限があり、それは複数のバックパックです、それはバックパックがいっぱいになることができるかどうかに依存します、01バックパックを解決するための次の2つのdp方法。
1. dp [i]は、容量iのパッケージを充填できるかどうかを示します。充填できる場合は、dp [i] = 1です。
2.dp [i]は、容量がiのバッグが保持できる最大値を表します。ここで、各重量の値は、重量自体に等しくなります。
最後に、1から始めて、合計して0の最初のdpを見つけます。これは、計量できない最小の重量です。
ACコード
解決策1:解決策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:解決策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;
}