【问题描述】
Gardon 昨天给小希布置了一道作业,即根据一张由不超过 5000 的 N(3<=N<=100)个正整数组成的数表两两相加得到 N*(N-1)/2 个和,然后再将它们排序。例如,如果数表里含有四个数 1,3,4,9,那么正确答案是 4,5,7,10,12,13。小希做完作业以后出去玩了一阵,可是下午回家时发现原来的那张数表不见了,好在她做出的答案还在,你能帮助她根据她的答案计算出原来的数表么?
【输入形式】
包含多组数据,每组数据以一个 N 开头,接下来的一行有按照大小顺序排列的 N*(N-1)/2 个数,是小希完成的答案。文件最后以一个 0 结束。
假设输入保证解的存在性和唯一性。
【输出形式】
对于每组数据,输出原来的数表。它们也应当是按照顺序排列的。
【样例输入】
4 4 5 7 10 12 13 4 5 6 7 8 9 10 0
【样例输出】
1 3 4 9 2 3 4 6
通过神奇的数学关系可以确定最小和次小是n1+n2,n1+n3
假设sum[i]是n2+n3,满足条件时,可以确定n1,n2,n3,
删除sum中的n1+n2,n1+n3,n2+n3,此时最小为n1+n4
可以确定出n4,删除n1+n4,n2+n4,n3+n4,此时最小为n1+n5
可以确实出n5,删除……,照此重复
其中某次若删除失败,则说明假设有误,继续向后假设
如果重复到最后无错误,则输出
#include <iostream>
#include <vector>
using namespace std;
bool Erase(vector<int>& tmp, int flag)
{
int n = tmp.size();
for (int i = 0; i < n; i++)
if (tmp[i] == flag)
{
tmp.erase(tmp.begin() + i);
return true;
}
return false;//找了一圈没找到要删除的,说明前面假设sum[i]是n2+n3有误
}
void input(vector<int> num)
{
int n = num.size();
for (int i = 0; i < n; i++)
cout << num[i] << ' ';
cout << endl;
}
void fun(vector<int> sum, int n, int N)
{
for (int i = 2; i < n; i++)//可以确定sum[0]是n1+n2,sum[1]是n1+n3
{//假设sum[i]是n2+n3
int c = sum[i] - sum[0];//n3-n1
int a = sum[i] - sum[1];//n2-n1
int b = sum[1] - sum[0];//n3-n2
if (a > 0 && b > 0 && c == a + b)//满足则sum[i]可能是真的n2+n3
{
vector<int> tmp(sum);//临时储存数据的向量
vector<int> num(N);//储存当前的n1、n2……
bool FLAG = true;//判断当前选定的sum[i]是否正确
num[0] = (sum[0] - a) / 2;//如果sum[0]-a是奇数肯定也不符合,在39行进行再判断
num[1] = num[0] + a;
num[2] = num[0] + c;
//样例:448 718 733 1060 1075 1345,满足i=2时c=a+b,但不满足以下判断
if (num[0] + num[1] != sum[0] || num[0] + num[2] != sum[1] || num[1] + num[2] != sum[i])
continue;
tmp.erase(tmp.begin() + i);//删除sum[i]即n2+n3
tmp.erase(tmp.begin() + 1);//删除sum[1]即n1+n3
tmp.erase(tmp.begin());//删除sum[0]即n1+n2
//完成上述操作后当前tmp中最小值是n1+n4
for (int curr = 3; curr < N; curr++)
{
num[curr] = tmp[0] - num[0];//n1+n[curr]-n1;
bool flag = true;
for (int i = 0; i < curr; i++)
{
flag = Erase(tmp, num[i] + num[curr]);//删除已知的
if (!flag)//如果删除失败了
{
FLAG = false;
break;
}
}
//完成上述删除后最小的变成n1+n[curr+1]
if (!FLAG)//已经确定当前选择有误
break;
}
if (FLAG)//当前假设正确,输出并退出,否则继续循环
{
input(num);
return;
}
}
}
}
int main()
{
int N = 0;
while (cin >> N, N)
{
int n = N * (N - 1) / 2;
vector<int> sum(n);
for (int i = 0; i < n; i++)
cin >> sum[i];
fun(sum, n, N);
}
return 0;
}