题目意思:给你n*(n-1)/2数字,这些数字是由n个数字选择两个数字相加的集合,问你构成这n*(n-1)/2的原n个数字分别是什么,保证有唯一解,还要从小到大输出。
题解思路:
知识点:组合数学+暴力枚举.
1.把这n*(n-1)/2个数字从小到大排序分别为K1,K2...KN...K(N-1)*N/2,假设这n个数字分别是A1,A2,...AN
2.从边缘出发,明显满足以下两个方程
2.1 A1+A2=K1(1) A1+A3=K2(2)
2.2但是由于不确定的关系,我们假设 A2+A3=KX(3<=x<=n)(3)
3.从3~n枚举KX,解出上面三个方程,得到解(A1,A2,A3),如果有正整数解,那么从(K1,K2...KN..)中去除A1+A2,A1+A3,A2+A3
4.假设我们已经得到了AK的值,那么要去除(A1+AK,A2+AK...,Ak-1+AK),这时假设剩下的最小的为Ki,显然Ki=A1+AK+1
5.整个的时间复杂度为N^3
#include<bits/stdc++.h>
#define register int rint
#define INF 0x3f3f3f3f3f
#define MOD 1000000007
#define mem(a,b) memset(a,b,sizeof(a))
#define PI 3.141592653589793
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>PII;
const int N=1e4+20;
const int Max=1e4+20;
const double esp=1e-6;
inline int rd() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int n,num[N],ans[N],vis[N];
ll total,A;
bool judge(int a,int b,int c)///判断这三个方程有没有整数解
{
int t1,t2,t3,a1,b1,c1;
t1=(c-a+b)/2;
t2=(a+c-b)/2;
t3=(a-c+b)/2;
a1=(a-c+b)%2==0&&(a-c+b)>0?1:0;
b1=(a+c-b)%2==0&&(a+c-b)>0?1:0;
c1=(c-a+b)%2==0&&(c-a+b)>0?1:0;
if(a1&b1&c1)
{
ans[3]=t1;
ans[2]=t2;
ans[1]=t3;
}
return a1&b1&c1;
}
bool get(int x)
{
vis[1]=1,vis[2]=1;vis[x]=1;///k2+k3 已经访问过了
int now=3,p=3;
for(int i=4;i<=n;++i)
{
int y=2;
while(vis[p]&&p<=(n-1)*n/2) {++p;}
if(p>(n-1)*n/2) return 1;
vis[p]=1;
ans[i]=num[p]-ans[1];
for(int j=p+1;j<=(n-1)*n/2;++j)
{
if(y==i) break;
if(vis[j]==0&&num[j]==ans[y]+ans[i])
{
vis[j]=1;
++y;
}
}
if(y!=i) return 0;
}
return 1;
}
int main()
{
while(cin>>n)
{
total=0;
for(int i=1;i<=(n-1)*n/2;++i)
{
num[i]=rd();
total+=num[i];
}
sort(num+1,num+1+(n-1)*n/2);
A=total/(n-1);
///cout<<A<<endl; a1+a2+...+an=A
for(int i=3;i<=n*(n-1)/2;++i)
{
if(judge(num[1],num[2],num[i])==0) continue;
mem(vis,0);
if(get(i))
{
for(int i=1;i<=n;++i)
cout<<ans[i]<<endl;
break;
}
}
}
}