POJ 3977 Subset | 折半搜索
题目:
给出一个整数集合,求出非空子集中元素和绝对值最小是多少(元素个数尽量少)
题解:
分成两半
爆搜每一半,用map维护前一半的值
每搜出后一半的一个值就去map里找和他和绝对值最小的更新答案
#include<cstdio> #include<algorithm> #include<cstring> #include<vector> #include<map> typedef long long ll; using namespace std; ll n,a[50],ans,tmp,ok; map <ll,ll> mp; map <ll,ll> :: iterator it; ll Abs(ll x){ return x>0?x:-x;} void DfsFront(ll step,ll state,ll val) { if (step>n/2) { it=mp.find(val); if (it!=mp.end()) mp[val]=min(mp[val],state); else mp[val]=state; if (Abs(val)<ans && state!=0) ans=Abs(val),tmp=state; if (Abs(val)==ans && state<tmp && state!=0) tmp=state; return ; } DfsFront(step+1,state,val); DfsFront(step+1,state+1,val+a[step]); } void DfsBack(ll step,ll state,ll val) { if (step>n) { it=mp.lower_bound(-val); ll w=it->first; if (it!=mp.end() && Abs(val+w)<ans && it->second+state!=0) ans=Abs(val+w),tmp=it->second+state; if (it!=mp.end() && Abs(val+w)==ans && mp[w]+state<tmp && mp[w]+state!=0) tmp=mp[w]+state; if (it!=mp.begin()) it--; if (it!=mp.end()) { w=it->first; if (Abs(val+w)<ans && state+it->second!=0) ans=Abs(val+w),tmp=it->second+state; if (Abs(val+w)==ans && it->second+state<tmp && it->second!=0) tmp=it->second+state; } return ; } DfsBack(step+1,state,val); DfsBack(step+1,state+1,val+a[step]); } int main() { while (scanf("%lld",&n)!=0,n) { mp.clear(); ans=mp[0]=0; for (int i=1;i<=n;i++) scanf("%lld",&a[i]),ans+=233+Abs(a[i]); DfsFront(1,0,0); DfsBack(n/2+1,0,0); printf("%lld %lld\n",ans,tmp); } return 0; }