(POJ 2549)Sumsets(折半枚举)
Description
![](http://poj.org/images/2549_1.jpg)
Input
Several S, each consisting of a line containing an integer 1 <= n <= 1000 indicating the number of elements in S, followed by the elements of S, one per line. Each element of S is a distinct integer between -536870912 and +536870911 inclusive. The last line of input contains 0.
Output
For each S, a single line containing d, or a single line containing "no solution".
Sample Input
5 2 3 5 7 12 5 2 16 64 256 1024 0
Sample Output
12 no solution
看数据范围想想就知道暴力不可行,这几天心血了另外一种枚举方法,折半枚举。
因为a+b+c=d;
所以式子可以化为a+b=d-c;
所以把暴力枚举的o(n^4)变成o(n^2);
先把所有的a+b枚举出来,用map记录其是否出现过,再枚举d-c,看看其对应的数字有没有出现。因为还要判断abcd互不相同,所以枚举时要注意条件。
PS:由于a+b可以小于0,用map方便一点。
#include<iostream> #include<cstdio> #include<vector> #include<set> #include<map> #include<string.h> #include<cmath> #include<algorithm> #include<queue> #define inf 0x3f3f3f3f using namespace std; int a[1010]; int n; class po { public: int a,b; po(int a1,int b1){a=a1,b=b1;} }; map<int,vector<po> > run; int solve() { for(int i=n;i>=1;i--) { for(int j=1;j<=n;j++) { if(j==i) continue; int tem=a[j]-a[i]; for(int k=0;k<run[tem].size();k++) { // cout << a[i] << " " << a[j] << endl; int a1=run[tem][k].a; int b1=run[tem][k].b; if(a[i]!=a1&&a[i]!=b1&&a[j]!=a1&&a[j]!=b1) return a[j]; } } } return 536870912; } int main() { while(~scanf("%d",&n)) { if(n==0) break; run.clear(); memset(a,0,sizeof(a)); for(int i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+1+n); for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { po tem(a[i],a[j]); run[a[j]+a[i]].push_back(tem); } } int ans=solve(); if(ans==536870912) printf("no solution\n"); else printf("%d\n",ans); } return 0; }
此地非逐弃者之王座,彼方乃行愿者之归所。无限清澈,星界银波。