AcWing 113 特殊排序

题目描述:

有N个元素,编号1.2..N,每一对元素之间的大小关系是确定的,关系不具有传递性。也就是说,元素的大小关系是N个点与N*(N-1)/2条有向边构成的任意有向图。然而,这是一道交互式试题,这些关系不能一次性得知,你必须通过不超过10000次提问来获取信息,每次提问只能了解某两个元素之间的关系。

现在请你把这N个元素排成一行,使得每个元素都小于右边与它相邻的元素。你可以通过我们预设的bool函数compare来获得两个元素之间的大小关系。例如,编号为a和b的两个元素,如果元素a小于元素b,则compare(a,b)返回true,否则返回false。将N个元素排好序后,把他们的编号以数组的形式输出,如果答案不唯一,则输出任意一个均可。

数据范围

1≤N≤1000

输入样例

[[0, 1, 0], [0, 0, 0], [1, 1, 0]]

输出样例

[3, 1, 2]

注意:不存在两个元素大小相等的情况。

分析:

本题与一般排序有三个区别,其一是交互式,你并不知道大小关系,只能通过调用compare接口询问;其二是大小不具备传递性,比如a < b,b < c并不能推出a < c;其三是不能超过一万次询问,数据范围为1000,nlogn略小于一万,而CBA算法在最坏情况下的下界也就是nlogn。

对于其第二个性质仅仅导致答案不唯一,题目仅要求输出一种答案,所以可以忽视该条件。采用二分插入排序解决该问题,首先将第一个元素压入向量里,然后二分查找合适的位置r,将待插入元素插入到向量末尾,从后往前不断交换相邻的两个数直到待插入的元素到达指定位置。注意该二分算法的写法,循环退出时l比r小一,意味着r位置的必然小于待插入的元素,r+1及其之后的元素都大于待插入的元素。

class Solution {
public:
    vector<int> specialSort(int N) {
        vector<int> res;
        res.push_back(1);
        for(int i = 2;i <= N;i++){
            int l = 0,r = res.size() - 1;
            while(l <= r){
                int mid = l + r >> 1;
                if(compare(res[mid],i)) l = mid + 1;
                else    r = mid - 1;
            }
            res.push_back(i);
            for(int j = res.size() - 2;j > r;j--)   swap(res[j],res[j + 1]);
        }
        return res;
    }
};

猜你喜欢

转载自blog.csdn.net/qq_30277239/article/details/87170734
113