题目描述
现有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。
主要思路 : 爆搜 + XJB剪枝 + XJB判重
对,就是爆搜。我们暴力搜索一下我们要哪几个砝码要选。这里就涉及一个XJB剪枝:我们记录一下这是我们有几个砝码不选,如果超过m的话就不能继续不选了。
我们枚举出了哪几个砝码要选后如何搞有多少重量可以称出来呢??
我们可以先把我们选的几个砝码的重量放在一个vector里好了,我们每次到一个要选砝码中,把vector中的每个重量加上当前选的砝码的重量,如果这个重量没有被出现过,就加入vector,然后把这个重量的判重bool数组相应位置标上。
code:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; #define go(i, j, n, k) for(int i = j; i <= n; i += k) #define fo(i, j, n, k) for(int i = j; i >= n; i -= k) #define rep(i, x) for(int i = h[x]; i; i = e[i].nxt) #define mn 22 #define mk 2010 #define inf 1 << 30 #define ll long long inline int read() { int x=0,f=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')f=-f;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int n, m, a[mn], maxx = -1, ans = 0; bool f[mk], b[mn]; vector<int> get; inline void get_ans(int x) { // 打完才想到可以直接循环QAQ,做题时写递归写傻了 if(x == n + 1) return; if(b[x]) { int kkk = get.size(); if(!f[a[x]]) get.push_back(a[x]); f[a[x]] = true; go(i, 0, kkk - 1, 1) { int zcy = get[i] + a[x]; if(!f[zcy]) get.push_back(zcy); f[zcy] = true; } } get_ans(x + 1); } inline void dfs(int x, int now) { if(x == n + 1) { if(now != m) return; // 初始化啊QwQ! ans = 0; memset(f, false, sizeof f); while(!get.empty()) get.pop_back(); get_ans(1); // 统计答案(上限为Σa[i],我很懒,直 // 接maxn * max(a[i])) go(i, 1, 2000, 1) if(f[i]) ans++; maxx = max(maxx, ans); return; } if(now > m) return; b[x] = true; dfs(x + 1, now); b[x] = false; // 有个不选的就要把计数 + 1 dfs(x + 1, now + 1); } int main() { n = read(), m = read(); go(i, 1, n, 1) a[i] = read(); dfs(1, 0); cout << maxx << "\n"; return 0; }