每日一题7.22

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

你可能感兴趣的:(每日一题,算法)