洛谷 P3067 [USACO12OPEN]Balanced Cow Subsets G
阿新 • • 發佈:2021-10-08
Description
P3067 [USACO12OPEN]Balanced Cow Subsets G
Solution
又是一道折半搜尋題。
我們還是列舉一半的數,記錄每一種情況的和。
然後爆搜另一半,當和為 \(S\) 時,判斷前一半是否可以湊出 \(S\),如果可以,打個標記即可。
兩次湊出 \(S\) 時,可能會有重複選用的陣列,但其實不用管。
考慮到重複的話,兩邊同時刪去同一個數也相等,但可能選用相同的數會多次出現,所以要打個標記。
\(dfs\) 過程中,狀壓記錄一下當前選用了哪些數,加和減狀壓相同的狀態也可以,前面證明過重複的數沒有影響了。
這道題由於還需要找到和為 \(S\)
所以還要用一個 \(map\) 離散化一下,不是真正的離散化,因為不需要排序,只需要標記一下即可。
程式碼還是比較容易理解的。
Code
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <map> #include <vector> #define ri register int using namespace std; const int N = 30; const int S = (1 << 20) + 10; int n, mid, cnt; int a[N]; map <int, int> mp; vector <int> g[S]; bool vis[S]; inline void dfs1(int x, int sum, int now){ // cout << "x " << x << " " << now << endl; if(x > mid){ if(!mp.count(sum)) mp[sum] = ++cnt; g[mp[sum]].push_back(now); return; } dfs1(x + 1, sum, now); dfs1(x + 1, sum + a[x], now | (1 << (x - 1))); dfs1(x + 1, sum - a[x], now | (1 << (x - 1))); } inline void dfs2(int x, int sum, int now){ if(x > n){ if(mp.count(sum)){ int t = mp[sum]; for(auto x : g[t]) vis[x | now] = 1; } return; } dfs2(x + 1, sum, now); dfs2(x + 1, sum + a[x], now | (1 << (x - 1))); dfs2(x + 1, sum - a[x], now | (1 << (x - 1))); } int main(){ scanf("%d", &n); for(ri i = 1; i <= n; i++) scanf("%d", &a[i]); mid = n >> 1; dfs1(1, 0, 0), dfs2(mid + 1, 0, 0); ri ans = 0; for(ri i = 1; i <= (1 << n); i++) ans += vis[i]; printf("%d\n", ans); return 0; }
End
本文來自部落格園,作者:{xixike},轉載請註明原文連結:https://www.cnblogs.com/xixike/p/15379931.html