P1441 砝码称重

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

观察数据范围, 有两点发现:

  1. (n) 较小
  2. (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;
	}
原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9794099.html