P1441 砝码称重
题目描述
现有n个砝码,重量分别为a1,a2,a3,……,an,在去掉m个砝码后,问最多能称量出多少不同的重量(不包括0)。
【数据规模】
对于20%的数据,m=0;
对于50%的数据,m≤1;
对于50%的数据,n≤10;
对于100%的数据,n≤20,m≤4,m<n,ai≤100。
Solution
观察数据范围, 有两点发现:
- (n) 较小
- (m) 非常小
所以想往搜索或状压这个方向(暴力)靠
这里用搜索解决问题
枚举不用的比枚举用的更优
我们 (dfs) 枚举不用的砝码
在枚举出一种状态后进行 可行性(dp)(01背包) 统计可行数, 暴力更新最优值即可
复杂度 (O(n^{m}n^{2}) = O(n^{m + 2}))
Code
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<climits>
#define LL long long
#define REP(i, x, y) for(int i = (x);i <= (y);i++)
using namespace std;
int RD(){
int out = 0,flag = 1;char c = getchar();
while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
return flag * out;
}
const int maxn = 25;
int num, m;
int ans, maxx;
int a[maxn];
bool can[maxn];
int dp[200019];
int DP(){
int ret = 0;
memset(dp, 0, sizeof(dp));
dp[0] = 1;
REP(i, 1, num){
if(can[i])continue;
for(int j = maxx;j >= a[i];j--){
dp[j] |= dp[j - a[i]];
}
}
REP(i, 1, maxx)ret += dp[i];
return ret;
}
void dfs(int Index, int tot){
if(tot >= m || Index > num){
if(tot == m)
ans = max(ans, DP());
return ;
}
can[Index] = 1;
dfs(Index + 1, tot + 1);
can[Index] = 0;
dfs(Index + 1, tot);
}
int main(){
num = RD(), m = RD();
REP(i, 1, num)a[i] = RD(), maxx += a[i];
dfs(1, 0);
printf("%d
", ans);
return 0;
}