思路:折半搜索,每个数的状态只有三种:不选、选入集合A、选入集合B,然后就暴搜出其中一半,插入hash表,然后再暴搜另一半,在hash表里查找就好了。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; #define maxn 25 int n; int a[maxn],t[maxn]; bool v[1025][1025]; int ans; struct hash_table{ static const int mod=242354; int tot,now[mod],pre[1000000],son[1000000],val[1000000]; void insert(int t,int x){ int pos=(x%mod+mod)%mod; for (int p=now[pos];p;p=pre[p]) if (son[p]==t&&val[p]==x) return; son[++tot]=t,val[tot]=x,pre[tot]=now[pos],now[pos]=tot; } int find(int t,int x){ int pos=(x%mod+mod)%mod,ans=0; for (int p=now[pos];p;p=pre[p]) if (val[p]==x&&!v[son[p]][t]){v[son[p]][t]=1;ans++;} return ans; } }H; void dfs1(int x,int val){ if (x>n/2){ int tmp=0;for (int i=1;i<=n/2;i++) tmp=tmp<<1|t[i]; H.insert(tmp,val);return; } t[x]=1;dfs1(x+1,val+a[x]); t[x]=0;dfs1(x+1,val); t[x]=1;dfs1(x+1,val-a[x]); } void dfs2(int x,int val){ if (x>n){ int tmp=0;for (int i=n/2+1;i<=n;i++) tmp=tmp<<1|t[i]; ans+=H.find(tmp,val); return; } t[x]=1;dfs2(x+1,val+a[x]); t[x]=0;dfs2(x+1,val); t[x]=1;dfs2(x+1,val-a[x]); } int main(){ scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&a[i]); dfs1(1,0),dfs2(n/2+1,0); printf("%d ",ans-1); return 0; }