题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=21246
题意:给定一个数字n,代表最多有n个方程解,再给出(n-1)*n/2个值a,对应不知道的任意两个数的和。把这些数的方案求出来,输出一种。若没有,输出Impossible
思路:线性方程组,看了题解才会做,比赛的时候都没什么人做说明大家其实挺LOW的。给a排序,其中a[0]和a[1]分别为x[0]+x[1]和x[0]+x[2]的解。这时候向后遍历a[k] = x[0]+x[2],得出x[2]。根据每次遍历最小值均为a[m] = x[m0]+x[0],把所有数标记上,若存在未标记的数,则此种情况不和条件,k向后,再次重复操作。
错误点第一是没有思路,对线性方程不熟悉,用了矩阵求秩的方法去求,结果繁琐不说,还带有很大的随机性。第二是不明白x[0]+x[m0](m0可以为任意值)<x[1]+x[2]的可存在性,注意m0为任意值。第三vis数组开小(MD)
源码:#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
int const MAXN = 10+5;
int a[MAXN*MAXN/2],b[MAXN],n,vis[MAXN*MAXN/2],m;
//int st[MAXN] = {0,0,1,3,6,10,15,21,27};
int gmin(int a,int b){return a<b?a:b;}
int find_min()
{
int i;
for(i=0; i<m; i++)
if(vis[i]==0)
break;
return i;
}
void del(int tt)
{
for(int i=0; i<m; i++){
if(a[i]==tt && vis[i]==0){
vis[i]=1;
return;
}
}
}
void check()
{
int i,j;
printf("a = ");
for(i=0; i<m; i++)
printf("%d ",a[i]);
printf("\nvis = ");
for(i=0; i<m; i++)
printf("%d ",vis[i]);
printf("\nb = ");
for(i=0;i<n; i++)
printf("%d ",b[i]);
printf("\n");
}
int main()
{
while(scanf("%d",&n)!=EOF){
int flag = 0;
memset(vis,0,sizeof(vis));
int i,j,k;
m = n*(n-1)/2;
for(i=0; i<m; i++)
scanf("%d",&a[i]);
sort(a,a+m);
for(k=2; k<m; k++){
// printf("\nk = %d\n",k);
flag = 0;
if((a[0]+a[1]-a[k])%2!=0){
flag = 1;
continue;
}
b[0] = (a[0]+a[1]-a[k])/2;
b[2] = a[1] - b[0];
b[1] = a[0] - b[0];
if(b[1]+b[2]!=a[k]){
flag = 1;
continue;
}
vis[0] = vis[1] = vis[k] = 1;
for(i=3; i<n; i++){
b[i] = a[find_min()] - b[0];
for(j=0; j<i; j++)
del(b[j]+b[i]);
}
for(i=0; i<m ;i++){
if(vis[i]==0){
flag = 1;
break;
}
}
// check();
memset(vis,0,sizeof(vis));
if(flag==0)
break;
}
if(flag)
printf("Impossible\n");
else{
sort(b,b+n);
int f = 1;
for(i=0; i<n; i++){
if(f) f=0;
else printf(" ");
printf("%d",b[i]);
}
printf("\n");
}
}
return 0;
}