P10451 Innovative Business - 洛谷
有 N 个元素,编号 1,2,…,N,每一对元素之间的大小关系是确定的,关系具有反对称性,但不具有传递性。
注意:不存在两个元素大小相等的情况。
也就是说,元素的大小关系是 N 个点与 2N×(N−1) 条有向边构成的任意有向图。
然而,这是一道交互式试题,这些关系不能一次性得知,你必须通过不超过 10000 次提问来获取信息,每次提问只能了解某两个元素之间的关系。
现在请你把这 N 个元素排成一行,使得每个元素都小于右边与它相邻的元素。
你可以通过我们预设的 bool 函数 compare 来获得两个元素之间的大小关系。
例如,编号为 a 和 b 的两个元素,如果元素 a 小于元素 b,则 compare(a,b) 返回 true,否则返回 false。
将 N 个元素排好序后,把他们的编号以数组的形式输出,如果答案不唯一,则输出任意一个均可。
为了适配 OJ,本题交互格式进行修改。改为 I/O 交互。
bool compare(int a, int b)
{
cout << "? " << a << ' ' << b << endl;
bool t;
cin >> t;
return t;
}
请在代码里填写此函数。擅自修改内容后果自负。
交互库会先给出一个正整数 N 表示元素数量。
之后的每次回答,交互库会返回 1 或 0 表示大小关系。1 代表 true,0 代表 false。
你可以使用题面中的 compare
函数进行提问。如要自己编写询问,询问格式为 ? a b
。
输出答案之前请先给出一个感叹号 !
。之后用空格分割这 n 个编号。具体见样例 #1.
输入 #1复制
3 1 0 0
输出 #1复制
? 1 2 ? 1 3 ? 2 3 ! 3 1 2
测试数据满足 1≤N≤1000。
Innovative Business.zip349.04KB
第一次做交互题,看题就看了半天。。。
最后又跑去看答案,看了一个归并解法一个二分解法,
以下是二分插入解法。
#include
using namespace std;
bool compare(int a, int b)
{
cout << "? " << a << ' ' << b << endl;
bool t;
cin >> t;
return t;
}
int main()
{
int n;
cin >> n;
vector res(1, 1);
for (int i = 2; i <= n; i++)
{
int l = 0;
int r=res.size()-1;
while (l < r)//最终保证i准备要插入到r的位置,让r~n都往右移,即i= r; j--)//r~n都向右移一位
swap(res[j], res[j + 1]);
}
cout << "! ";
for (int i = 0; i < res.size(); i++)
cout << res[i] << ' ';
cout << endl;
return 0;
}
#include
#include
using namespace std;
// 交互比较函数:返回a是否小于b(由用户输入或题目规则决定)
bool compare(int a, int b) {
cout << "? " << a << ' ' << b << endl;
bool t;
cin >> t;
return t;
}
// 归并排序:对数组arr的[l,r]区间进行排序
void mergeSort(vector& arr, int l, int r) {
// 递归终止条件:区间长度为1或为空
if (l >= r) return;
// 计算中间点,避免整数溢出
int mid = l + (r - l) / 2;
// 分治:递归排序左右子数组
mergeSort(arr, l, mid); // 排序左半部分 [l, mid]
mergeSort(arr, mid + 1, r); // 排序右半部分 [mid+1, r]
// 合并两个有序子数组
vector temp(r - l + 1); // 临时数组存储合并结果
int i = l, j = mid + 1, k = 0; // i指向左子数组,j指向右子数组,k指向临时数组
// 比较左右子数组当前元素,按升序放入临时数组
while (i <= mid && j <= r) {
if (compare(arr[i], arr[j])) // 如果arr[i] < arr[j]
temp[k++] = arr[i++]; // 取左子数组元素
else
temp[k++] = arr[j++]; // 取右子数组元素
}
// 将剩余元素复制到临时数组(左右子数组中可能有一个未遍历完)
while (i <= mid) temp[k++] = arr[i++];
while (j <= r) temp[k++] = arr[j++];
// 将临时数组复制回原数组
for (i = l, k = 0; i <= r; i++, k++) arr[i] = temp[k];
}
int main() {
int n;
cin >> n; // 读取元素个数
// 初始化数组为1到n
vector a(n);
for (int i = 0; i < n; i++) a[i] = i + 1;
// 使用归并排序对数组进行排序
mergeSort(a, 0, n - 1);
// 输出排序结果
cout << "! ";
for (int num : a) cout << num << ' ';
return 0;
}