传送门:点击打开链接
分析:一看感觉就是dfs加一些优化,首先想到的是剪枝,但是效果不理想,某些特定的数据还是会超时,后面看了别人的代码才恍然大悟,用二分!,具体来说就是拆分为两个子集,时间复杂度降为O(2^n/2),前后两次dfs,第一次记录次数,第二次统计答案。((b+d)/(a+c)=x/y ---> a*x-b*y=d*y-c*x a,b为前半个集合某个子集水和盐的含量,c,d为后半个子集水和盐的含量)。另外,c++中的map<int,int>可以做为一个大数组来用。
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long const int N = 40; ll t,m,n,x,y,s,a[N],b[N]; map<ll,ll> mp; void dfs(ll i,ll j,ll k){ if(k==m+1) { mp[j*x-i*y]++; return ; } dfs(i+a[k],j+b[k],k+1); dfs(i,j,k+1); } void DFS(ll i,ll j,ll k){ if(k==n) { s+=mp[i*y-j*x]; return ; } DFS(i+a[k],j+b[k],k+1); DFS(i,j,k+1); } int main(){ cin>>t; while(t--){ cin>>n>>x>>y; m=n/2; for(int i=0;i<n;i++) cin>>a[i]>>b[i]; dfs(0,0,0); DFS(0,0,m+1); cout<<s-1<<endl;///减去空集 即两个子集都为0的情况 s=0; mp.clear(); } return 0; }