题目链接:
http://poj.org/problem?id=3628
题目大意:
有n个数字(1~100W),现在有一个数b,1<=b<=s(s为n个数字之和)。要从n个数字中选择一些数字组合,有一写组合的数字之和x会大于等于b, 求所有x中x-b最小的是多少?
思路:
刚开始看到这题,发现数字这么大,以为内存不够不能用背包。而n最大才20,所以直接用dfs+减枝0MS过了。。。
然后用背包,开了2000W+的数组,memset初始化,果断地MLE了。。。然后看了下discuss,发现用memset会增加很多额外的内存。
于是改用for循环初始化,内存就够用了。然后就是赤裸的01背包了
后话:
这题数据水得够可以,dp开20W数组都过了,暴力2^20的复杂度也无压力过
dfs + 减枝 0MS:
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<cmath>
typedef long long int64;
const int MAXN = 1000010;
const int INF = 0x3f3f3f3f;
int n, b;
int h[25];
int sum[25];
int ans;
void dfs(int cur, int tol){
if(cur>n+1 || ans==b)return;
if(tol >= ans)return;
if(tol >= b){
ans = min(tol, ans);
return ;
}
if(tol + sum[n] - sum[cur-1] < b)
return;
dfs(cur+1, tol);
dfs(cur+1, tol+h[cur]);
}
int main(){
while(~scanf("%d%d", &n, &b)){
sum[0] = 0;
for(int i=1; i<=n; ++i){
scanf("%d", &h[i]);
if(i==0) sum[0]=h[i];
else sum[i] = sum[i-1]+h[i];
}
ans = INF;
dfs(1, 0);
printf("%d\n", ans-b);
}
return 0;
}
背包1:
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<cmath>
#define MP make_pair
#define SQ(x) ((x)*(x))
using namespace std;
typedef long long int64;
const int MAXN = 1000010;
const int INF = 0x3f3f3f3f;
int n, b;
int h[25];
int ans;
int f[20000010];
int main(){
while(~scanf("%d%d", &n, &b)){
int sum = 0;
for(int i=1; i<=n; ++i){
scanf("%d", &h[i]);
sum += h[i];
}
for(int i=0; i<=sum; ++i)
f[i] = 0;
for(int i=1; i<=n; ++i)
for(int v=sum; v>=h[i]; --v)
f[v] = max(f[v], f[v-h[i]]+h[i]);
int ans = INF;
for(int v=b; v<=sum; ++v)
if(f[v]>=b && f[v]-b < ans)
ans = Abs(f[v]-b);
printf("%d\n", ans);
}
return 0;
}
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int INF = 0x3f3f3f3f;
int n, b;
int h[25];
int ans;
bool f[20000010];
int main(){
while(~scanf("%d%d", &n, &b)){
int sum = 0;
for(int i=1; i<=n; ++i){
scanf("%d", &h[i]);
sum += h[i];
}
for(int i=1; i<=sum; ++i)
f[i] = false;
f[0] = true;
for(int i=1; i<=n; ++i)
for(int v=sum; v>=h[i]; --v)
if(f[v-h[i]])
f[v] = true;
int ans = INF;
for(int i=b; i<=sum; ++i)if(f[i]){
printf("%d\n", i-b);
break;
}
}
return 0;
}