HNU程序设计训练——小希的数表

【问题描述】

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;
}

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值