zoukankan      html  css  js  c++  java
  • PAT1067. Sort with Swap(0, *) (25) 并查集

    PAT1067. Sort with Swap(0, *) (25) 并查集

    题目大意

    给定一个序列, 只能进行一种操作: 任一元素与 0 交换位置, 问最少需要多少次交换.

    思路

    最优解就是每次 0 都和所在位置本应在的元素交换位置, 共 n - 1 次, 但是在交换中 0 可能会被交换到 0 号位置.

    仔细思考一下, 其实每次换到 0 就是一个图的连通分量, 按照输入的次序和输入的值, 可以求出图共有多少个联通分量.

    每个联通分量若要换回去, 需要 n - 1 次交换, 但是只能用 0 交换, 所以不含 0 且 结点个数不为 1 的连通分量需要进行 加 2 操作 (把 0 换进来, 排序, 再把 0 换出去).

    代码

    #include <cstdio>
    #include <cstring>
    #define MAXN 100100
    using namespace std;
    int arr[MAXN];
    int cnt[MAXN];
    int getFather(int a){
        if(a == arr[a])
            return a;
        return arr[a] = getFather(arr[a]);
    }
    void merge(int a, int b){
        a = getFather(a);
        b = getFather(b);
        if(a < b)
            arr[b] = a;
        else
            arr[a] = b;
    }
    int main(){
        int nNum;
        scanf("%d", &nNum);
        for(int i = 0; i < nNum; arr[i] = i++);
        for(int i = 0; i < nNum; i++)
            arr[i] = i;
    
        for(int i = 0; i < nNum; i++){
            int val;
            scanf("%d", &val);
            merge(i, val);
        }
    
        for(int i = 0; i < nNum; i++){
            cnt[arr[i]]++;
        }
    
        int sum = 0;
        for(int i = 0; i < nNum; i++){
            if(arr[i] != i)
                continue;
            sum += cnt[i] - 1;
            if(i != 0 && cnt[i] != 1)
                sum += 2;
        }
        printf("%d", sum);
        return 0;
    }
    
    
  • 相关阅读:
    新年后的第一个学习总结
    2021/02/07周学习总结
    内网穿透
    有效的括号
    实现一个简单的模板字符串替换
    二叉树的最大深度
    前端性能和错误监控
    前端缓存
    display: none; opacity: 0; visibility: hidden;
    发布订阅模式与观察者模式
  • 原文地址:https://www.cnblogs.com/1pha/p/7804213.html
Copyright © 2011-2022 走看看