zoukankan      html  css  js  c++  java
  • Codeforces 441D Valera and Swaps(置换群)

    题意:

      给定一个1~n的排列(n<=3000),输出字典序最小且次数最少的交换操作,使得操作后的排列可以通过最少m次交换得到排列[1,2,...n]

    Solution:

      可以将排列的对应关系看做边,f[i]=i,代表自环。那么根据置换原理,图中有k个环,则需要最少n-k次交换操作得到排列[1,2...n]。所以,先找出图中的环,对同一个环的位置进行标记。这样对不在同一个环的两个位置进行交换,会将两个环合并。将在同一个环内的两个位置进行交换,会将这个环分成两个环。

         只需要,判断需要加环还是去环。贪心选择序号较小的位置即可。

    /*
        置换群
    */
    #include <bits/stdc++.h>
    using namespace std;
    
    const int MAXN = 3009;
    
    int f[MAXN], g[MAXN], pos[MAXN];
    
    int n, m, ans, sum, t;
    int  main() {
        scanf ("%d", &n);
        for (int i = 1; i <= n; i++)
            scanf ("%d", &g[i]), pos[g[i]] = i;
    
        scanf ("%d", &m);
    
        for (int i = 1; i <= n; i++)
            if (!f[i]) {
                f[i] = ++sum;
                for (int x = i; !f[g[x]]; x = g[x])    f[g[x]] = f[i];
            }
    
        t = n - sum;
        printf ("%d
    ", m - t > 0 ? m - t : t - m);
    
        for (int i = 2; t < m; i++)
            if (f[1] != f[i]) {
                t++;
                for (int x = i; f[x] != f[1]; x = g[x])        f[x] = f[1];
                printf ("1 %d ", i);
            }
    
        for (int i = 1; t > m; i++) {
            if (g[i] != i)
                for (int j = i + 1; j <= n && t > m; j++)
                    if (f[i] == f[j]) {
                        printf ("%d %d ", i, j);
                        swap (g[i], g[j]);
                        t--;
                        if (g[i] == i) {
                            f[i] = -1; break;
                        }
                        else
                            f[i] = f[g[i]];
    
                        if (g[j] == j)  f[j] = -1;
                        else {
                            f[j] = ++sum;
                            for (int x = j; f[g[x]] != sum; x = g[x])        f[g[x]] = sum;
                        }
                    }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    JZOJ6096 森林
    HIT暑期集训 二分图匹配
    HIT暑期集训 网络流
    HIT暑期集训 tarjan,dfs序
    HIT暑期集训 图论基础
    HIT暑期集训 AC自动机
    HIT第二周 周测补题
    HIT暑期集训 字符串
    HIT暑期集训 动态规划
    HIT暑期集训 平衡树
  • 原文地址:https://www.cnblogs.com/keam37/p/4388654.html
Copyright © 2011-2022 走看看