[Cogs]-1032-最小交换排序

来源:互联网 发布:阿里云服务器申请退款 编辑:程序博客网 时间:2024/05/22 01:53

奇♂怪的题,我用了丧心病狂的方法,有必要写下题解

最小交换排序

【问题描述】

    小x最近切了一道很水的排序题,但是在AC之后,他想到了一个问题:

给定n个不相等的整数,将其按从小到大排序,你每次可以对任意一对数进行交换,问最少的交换次数是多少?

【输入】

第一行:一个整数n

第二行:n个用空格隔开的正整数ai,-2^31<ai<2^31

【输出】

一个整数,表示最小交换次数。

【输入输出样例】

minsort.inminsort.out88 23 4 16 77 -5 53 100 5

【数据范围】

   20%   n<=100

   50%   n<=5000

   100%  n<=100000

 

根据dw定理可以推出答案的值就是最长上升子序列的长度(参见我写的偏序集Dilworth定理证明及应用)

但说是丧心病狂,我们就有丧心病狂的方法,最长上升子序列O(n*logn)但我们用O(n)的方法,并且常数还比较小

先把{ai}离散化到{bi}

比如我们输入的{ai}是 2  9  18  36  7

{bi}:1  3  4  5  2

答案等价于我们把bi变成1 2 3 4 5   也就是b[i] = i(废话

这里我们的策略是到第i位时,把实际在第i位的数b[i]和应该在第i位的数i调换位置(当然了di == i时不用换了

那么问题就来了,挖掘机技术哪家强?

好吧,问题是我们怎么知道要和bi交换的i在哪里?

我们再来一个数组{fi}保存{bi}中数字i的位置,做出{fi}的原理也和{ai}变到{bi}一样离散一下(就是不用排序

我们就把b[i]和b[f[i]]交换位置就行了

但是交换了还得再调整部分fi的值

b[f[i]](数值为i)上的值变成了b[i]所以f[b[i]](b[i]的位置改了所以f[b[i]]要改)要改,改成什么呢?

b[i]是和i(b[f[i]])交换的,所以b[i]的位置要变成原来i的位置,i的位置又是f[i],所以f[b[i]]改成f[i]

 

还要变的是f[i],b[i]和i换了,所以i的位置就是i,也就是f[i] = i;

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<vector>#include<set>#include<map>#include<queue>#define maxn 100010using namespace std;struct node{    int x, num;} a[maxn];bool cmp(node a, node b){    return a.x < b.x;}int b[maxn], f[maxn], ans, n;inline void solve(){    scanf(“%d”, &n);    for (int i = 0; i < n; i++)    {        scanf(“%d”, &a[i].x);        a[i].num = i;    }    sort(a, a + n, cmp);    for (int i = 0; i < n; i++)        b[a[i].num] = i;    for (int i = 0; i < n; i++)        f[b[i]] = i;    int t;    for (int i = 0; i < n; i++)    {        if (f[i] != i)        {            f[b[i]] = f[i];            t = b[i];            b[i] = b[f[i]];            b[f[i]] = t;            f[i] = i;            ans ++;        }    }    return ;}int main(){    freopen(“minsort.in”, “r”, stdin);    freopen(“minsort.out”, “w”, stdout);    solve();    printf(“%d”, ans);    return 0;}
http://www.laomaotao.net/?E3887

0 0