1 条题解
-
0
解题思路
-
问题转化:
- 这是一个典型的"逆问题",即从结果反推原始数据。
- 我们需要从N*(N-1)/2个两两之和中恢复出N个原始数。
-
关键观察:
- 假设原始数按升序排列为a₁ ≤ a₂ ≤ ... ≤ a_N
- 最小的和一定是a₁ + a₂
- 第二小的和一定是a₁ + a₃
- 最大的和一定是a_{N-1} + a_N
- 次大的和一定是a_{N-2} + a_N
-
求解步骤:
- 首先对输入的和进行排序
- 通过最小的和a₁ + a₂和次小的和a₁ + a₃,可以求出a₁
- 然后可以依次求出其他数
- 需要验证所有两两之和是否匹配
-
特殊情况处理:
- 当N=3时,可以直接解方程组
- 对于更大的N,需要更复杂的推导和验证
代码分析
提供的代码实际上解决的是一个完全不同的棋盘覆盖问题(使用匈牙利算法解决二分图匹配),与题目要求的"从两两之和恢复原始数"问题无关。正确的解法应该:
- 读取输入数据
- 对和进行排序
- 根据数学关系推导可能的原始数
- 验证推导结果是否满足所有两两之和
- 输出结果或"Impossible"
注意事项
-
输入处理:
- 需要正确读取N和后续的和
- 注意处理多组测试数据
-
数学推导:
- 要确保推导过程的数学正确性
- 特别是边界情况的处理
-
验证步骤:
- 必须验证所有两两之和是否匹配
- 这是判断解是否正确的关键
-
输出要求:
- 结果需要按非递减顺序排列
- 多个解时输出任意一个即可
-
效率考虑:
- 由于N的范围很小(2<N<10),不需要考虑复杂度过高的问题
- 但仍应避免不必要的计算
示例解法思路
以第一个输入为例: 输入:3 1269 1160 1663
- 排序得到:1160, 1269, 1663
- 设三个数为a ≤ b ≤ c
- 有: a + b = 1160 a + c = 1269 b + c = 1663
- 解得: c = (1269 + 1663 - 1160)/2 = 886 a = 1269 - 886 = 383 b = 1160 - 383 = 777
- 验证:383+777=1160, 383+886=1269, 777+886=1663
- 输出:383 777 886
无解情况
当方程组无解或验证不通过时,输出"Impossible"。例如第二个输入: 输入:3 1 1 1 试图解方程: a + b = 1 a + c = 1 b + c = 1 解得a=b=c=0.5,但要求整数解,故输出"Impossible"。
标程
#include <iostream> #include <vector> #include <algorithm> #include <map> using namespace std; bool solve(int N, vector<int>& sums, vector<int>& result) { int total = N * (N - 1) / 2; if (sums.size() != total) return false; sort(sums.begin(), sums.end()); for (int x = 2; x < total; ++x) { int a1_plus_a2 = sums[0]; int a1_plus_a3 = sums[1]; int a2_plus_a3 = sums[x]; if ((a1_plus_a2 + a1_plus_a3 - a2_plus_a3) % 2 != 0) continue; int a1 = (a1_plus_a2 + a1_plus_a3 - a2_plus_a3) / 2; int a2 = a1_plus_a2 - a1; int a3 = a1_plus_a3 - a1; if (a1 > a2 || a2 > a3) continue; vector<int> temp_result; temp_result.push_back(a1); temp_result.push_back(a2); temp_result.push_back(a3); map<int, int> freq; for (vector<int>::iterator it = sums.begin(); it != sums.end(); ++it) { freq[*it]++; } freq[a1_plus_a2]--; freq[a1_plus_a3]--; freq[a2_plus_a3]--; if (freq[a1_plus_a2] == 0) freq.erase(a1_plus_a2); if (freq[a1_plus_a3] == 0) freq.erase(a1_plus_a3); if (freq[a2_plus_a3] == 0) freq.erase(a2_plus_a3); bool valid = true; for (int k = 3; k < N; ++k) { if (freq.empty()) { valid = false; break; } int next_sum = freq.begin()->first; int next_a = next_sum - a1; for (int j = 0; j < k; ++j) { int pair_sum = temp_result[j] + next_a; if (freq.find(pair_sum) == freq.end() || freq[pair_sum] == 0) { valid = false; break; } freq[pair_sum]--; if (freq[pair_sum] == 0) { freq.erase(pair_sum); } } if (!valid) break; temp_result.push_back(next_a); } if (valid) { sort(temp_result.begin(), temp_result.end()); result = temp_result; return true; } } return false; } int main() { int N; while (cin >> N) { int total = N * (N - 1) / 2; vector<int> sums(total); for (int i = 0; i < total; ++i) { cin >> sums[i]; } vector<int> result; if (solve(N, sums, result)) { for (int i = 0; i < N; ++i) { if (i > 0) cout << " "; cout << result[i]; } cout << endl; } else { cout << "Impossible" << endl; } } return 0; }
-
- 1
信息
- ID
- 1467
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 3
- 已通过
- 1
- 上传者