Problem Description
Yanghee 是一个小学生。他的数学老师给全班同学布置了一道家庭作业,即根据
一张不超过5000的n(n<50)个正整数组成的数表,两两相加得到n(n-1)/2个和,然后把它们排序。例如,如果数表含有四个数1,3,4,9,那么正确答案是4,5,7,10,12,13。Yanghee 做完作业以后和小伙伴们出去玩了一下午,回家以后发现老师给的数表不见了,可是他算出的答案还在。你能帮助Yanghee根据他的答案计算出原来的数表吗?
Input
输入第1行是1个正整数N,3<=n<50.然后有若干行,每行10个正整数,共计n(n-1)/2个数. 输入的数据有唯一解.
Output
按从小到大输出n个数x[1],x[2],…,x[n],每行1个,使得任意2个数之和恰是输入的n(n-1)/2个数.
Sample Input
15
3 4 5 6 7 8 9 10 11 12
13 14 15 16 5 6 7 8 9 10
11 12 13 14 15 16 17 7 8 9
10 11 12 13 14 15 16 17 18 9
10 11 12 13 14 15 16 17 18 19
11 12 13 14 15 16 17 18 19 20
13 14 15 16 17 18 19 20 21 15
16 17 18 19 20 21 22 17 18 19
20 21 22 23 19 20 21 22 23 24
21 22 23 24 25 23 24 25 26 25
26 27 27 28 29
Sample Output
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
这是一道非常经典的递推题,但是这个题目描述的我认为是有些问题的,题目上说将这些数进行排序,但是和样例输入中所给的情况是不一样的,个人感觉可能是出题人在造数据时进行了一些简化,经过我多次探索,发现其实对于这个输入中的数表根本不需要排序,直接做就可以Ac。
那么来说说本题的思路:首先找到最小的那个数,(我们假设原数表中最小的三个数分别为x,y,z,x小于y小于z)很明显,最小的那个数a[1]是等于x+y的,同理x+z=a[2],但是y+z就不一定=a[3]了,我们需要枚举来寻找答案,我们需要枚举3~n(n-1)/2吗?答案是否,因为y+z最大是不会超过a[n]的(这是因为比y+z要小的只可能是a[1]+a[k],当k取完2~n时,最小的就是a[2]+a[3]了),这样,本题的枚举范围就大大缩小了。
最后就很容易了,直接用a[1]~a[n-1]减去x即可得到所有的值(这是因为题目对于数据有所简化)。
对了,有一点要补充,在解方程是,我们是有如下简化方法的(应该是初中学的东西了)
x+y=a.....1
y+z=b.....2
x+z=c.....3
1+2+3得:2*(x+y+z)=a+b+c;
所以:x+y+z=(a+b+c)/2.....4
4-1可得z;
4-2可得x;
4-3可得y;
这些写法在代码中都有体现。
接下来上代码:
#include<bits/stdc++.h>
using namespace std;
int n,a[1500],b[55];
int main(){
scanf("%d",&n);
int m=(n*(n-1))/2;
for(int i=1;i<=m;i++)
scanf("%d",&a[i]);
int x,y,z;
for(int i=3;i<=n+1;i++){
int sum=a[1]+a[2]+a[i];
if(sum%2==1)continue;//因为要除以2 所以不是偶数无解
sum=sum/2;
x=sum-a[3];
y=sum-a[2];
z=sum-a[1];
//求解x,y,z
if(x>0&&y>0&&z>0)//找到解
break;
}
b[1]=x;
b[2]=y;
b[3]=z;
for(int i=1;i<n;i++)
b[i+1]=a[i]-x;//递推出其他解
for(int i=1;i<=n;i++)
printf("%d\n",b[i]);//输出
return 0;
}
以上为个人见解,代码是原创,希望大家多多评论指正。