POJ3977-Subset

    xiaoxiao2024-12-24  12

    35个数字意味着2^35种可能性,穷举是不可能的,因此我们采用二分搜索。 首先枚举一半的可能性存入map容器中,并不断更新答案,因为有可能这一部分中的答案就是最后的答案。同样枚举另一半的可能性,更新答案,但是要注意与上一部份的答案相结合。

    #include <cstdio> #include <map> #include <algorithm> using namespace std; typedef pair<long long, int> P; long long a[40]; long long abs(long long x) { return x >= 0 ? x : -x; } int main(int argc, char const *argv[]) { int n; while (scanf("%d", &n) == 1 && n) { for (int i = 0; i < n; i++) { scanf("%lld", &a[i]); } map<long long, int> mp; //保存答案:最小绝对值及选取个数 P res = make_pair(abs(a[0]), 1); for (int i = 1; i < (1 << (n / 2)); i++) { long long sum = 0; int cnt = 0; for (int j = 0; j < n / 2; j++) { if ((i >> j) & 1) { sum += a[j]; cnt++; } } //只从前半部分选取答案 res = min(res, make_pair(abs(sum), cnt)); if (mp[sum] != 0) { mp[sum] = min(mp[sum], cnt); } else { mp[sum] = cnt; } } for (int i = 1; i < (1 << (n - n / 2)); i++) { long long sum = 0; int cnt = 0; for (int j = 0; j < n - n / 2; j++) { if ((i >> j) & 1) { sum += a[n/2+j]; cnt++; } } //只从后半部分选取答案 res = min(res, make_pair(abs(sum), cnt)); //同时从两个部分选取答案 map<long long, int> :: iterator ite; ite = mp.lower_bound(-sum); if (ite != mp.end()) { res = min(res, make_pair(abs(ite->first + sum), ite->second + cnt)); } if (ite != mp.begin()) { ite--; res = min(res, make_pair(abs(ite->first + sum), ite->second + cnt)); } } printf("%lld %d\n", res.first, res.second); } return 0; }
    转载请注明原文地址: https://ju.6miu.com/read-1294956.html
    最新回复(0)