BoatBurglary - ACM练习

时间:2014-06-22 15:25:09

标签: c++ algorithm np acm

我正在尝试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中的子集问题,所以它不适用于这种情况。

您对我如何解决这个问题有任何想法吗?

2 个答案:

答案 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;
}

告诉我你的想法