我正在尝试this problem:
Rachid住在船上,并且只拥有一些物品,确切地说。 他非常注意自己的物品,并测量了每件物品的重量 它们具有高精度。项目i加权Wi微克。一个晚上一个 小偷访问他的船,并给一些物品钢。拉希德注意到了 第二天早上,因为船很轻,他可以测量 这个差异为D微克的水位。他想 通过检查这些权重,知道丢失了多少项目 请你帮忙。
输入
输入的第一行包含测试用例的数量,T。测试用例如下。每个案例由两行组成,第一行 包含两个整数N和D,用空格分隔。然后第二个 line包含n个整数,表示所有项的权重, 以空格分隔。
输出继电器
对于每个测试用例输出一行包含" Case #x:y",其中x是案例编号(从1开始)。如果缺少物品的数量 可以确定,那么y是这个数字。如果有几个 问题的答案是字符串" AMBIGIOUS"如果没有 回答y是字符串" IMPOSSIBLE" (为了清晰起见而添加了引号 不是输出的一部分。)
Limits 1<=T<=20 1<=N<=30 0<=Wi<=10^9
我首先想到这是经典的子集问题,即我们必须找到有多少子集的和等于D. NP中的子集问题,所以它不适用于这种情况。
您对我如何解决这个问题有任何想法吗?
答案 0 :(得分:1)
将项目拆分为最多15个堆。找到每个堆的每个子集的大小。将第二堆的所有子集放入由大小索引的哈希表中,并且对于第一堆的每个子集,查看哈希表以查看是否存在具有正确权重的内容。
答案 1 :(得分:0)
感谢tmyklebu,这是我的代码:
#include <fstream>
#include <cstdio>
#include <string.h>
#include <iostream>
#include <sstream>
#include <map>
#include <bitset>
using namespace std;
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define CLR(T, V) memset(T, V, sizeof T)
typedef unsigned long long u;
/* ---------------------- BEGIN ----------------------- */
const int NN = 100;
int W[NN];
int count_bits(int i) {
int c;
for (c = 0; i; c++)
i &= i - 1; // clear the least significant bit set
return c;
}
u sum_subset(int S, int offset=0) {
bitset<64> bs(S);
u sum = 0;
FOR(i, 0, 64)
if (bs[i]) sum += W[offset + i];
return sum;
}
string int_to_string(int i) {
ostringstream stream;
stream << i;
return stream.str();
}
string solve(int N, int D) {
map<u, int> sum;
map<u, int> nb_arg_sum;
int pile_size = (N+1) / 2;
int nb_subsets = 1 << pile_size;
FOR(i, 0, nb_subsets) {
u s = sum_subset(i);
map<u, int>::iterator it = sum.find(s);
if (it == sum.end())
nb_arg_sum[s] = 1;
else if(nb_arg_sum[s] == 1) {
nb_arg_sum[s] = 2 - (count_bits(i) == count_bits(it->second));
}
sum[s] = i;
}
int nb_sol = 0;
int sol = - 1;
nb_subsets = 1 << (N - pile_size);
FOR(i, 0, nb_subsets) {
u s = sum_subset(i, pile_size);
map<u, int>::iterator it = sum.find(D - s);
if (it != sum.end()) {
int sol2 = count_bits(i) + count_bits(it->second);
if ( (sol >= 0 && sol != sol2) || nb_arg_sum[D - s] > 1) return "AMBIGIOUS";
sol = sol2;
}
}
return (sol >= 0) ? int_to_string(sol) : "IMPOSSIBLE";
}
int main() {
#ifndef ONLINE_JUDGE
ifstream input("input.txt");
#define cin input
#endif
int T; cin >> T;
FOR(i, 0, T) {
CLR(W, 0);
int N, D;
cin >> N >> D;
FOR(j, 0, N) cin >> W[j];
cout << "Case #" << i + 1 << ": " << solve(N, D) << endl;
}
#ifndef ONLINE_JUDGE
system("pause");
#endif
return 0;
}
告诉我你的想法