zoukankan      html  css  js  c++  java
  • 并查集模板

    路径压缩+按秩合并

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 const int maxn=500010;
     6 int a[maxn], n;
     7 int fa[maxn];
     8 int rank[maxn];
     9 
    10 void init() {
    11     for(int i=1;i<=n; i++) {
    12         fa[i]=i;
    13         rank[i]=0;
    14     }
    15     return ;
    16 }
    17 
    18 int find(int z) {
    19     if(fa[z]!=z) 
    20         return fa[z]=find(fa[z]);
    21     return fa[z];
    22 }
    23 
    24 void unionn(int x,int y) {
    25     x=find(x);
    26     y=find(y);
    27     if (x==y) return ;
    28     if(rank[x]<rank[y]) {
    29         fa[x]=y;
    30     } 
    31     else {
    32         fa[y]=x;
    33         if (rank[x]==rank[y])
    34          rank[x]++;
    35     }
    36     return;
    37 }

    例题

    洛谷T3766

    //find与fa引发的血案

    题目描述

    有一个 M 行 N 列的点阵,相邻两点可以相连。一条纵向的连线花费一个单位,一条横向的连线花费两个单位。某些点之间已经有连线了,试问至少还需要花费多少个单位才能使所有的点全部连通。

    输入输出格式

    输入格式:

    第一行输入两个正整数 m 和 n。

    以下若干行每行四个正整数 x1,y1,x2,y2, 表示第 x1 行第 y1 列的点和第 x2 行第 y2 列的点已经有连线。输入保证|x1-x2|+|y1-y2|=1。

    输出格式:

    输出使得连通所有点还需要的最小花费。

    输入输出样例

    输入样例#1:
    2 2
    1 1 2 1
    输出样例#1:
    3

    说明

    30%数据: n*m<=1000

    100%数据: m,n<=1000

    标程

    //find与fa引发的血案

     1 #include <iostream>
     2 #include <cstdio>
     3 using namespace std;
     4 int m, n, tot, ans;
     5 int fa[1000010]; //father x,y=fa[x*1000+y]
     6 
     7 int find(int z) {
     8     if (fa[z]!=z) fa[z]=find(fa[z]);
     9     return fa[z];
    10 }
    11 
    12 int unionn(int x, int y) {
    13     x=find(x);
    14     y=find(y);
    15     if (x!=y) fa[x]=y;
    16 }
    17 
    18 int main() {
    19     cin >> m >> n;
    20     int sum = m*n;
    21     for (int i=1; i<=sum; i++) fa[i]=i;
    22     int x1,y1,x2,y2;
    23     while (cin>>x1>>y1>>x2>>y2) {
    24         unionn((y1-1)*m+x1,(y2-1)*m+x2);
    25     }
    26     for (int i=1; i<=sum; i++) 
    27         if (fa[i]==i) tot++;
    28     if(tot==1) { cout<<ans; return 0; }
    29     for (int i=1; i<=n; i++) { //对于每一列A[i] 
    30         for (int j=1; j<m; j++) { //枚举a[i][j]&a[i][j+1]是否联通 
    31             int k=(i-1)*m+j;
    32             if (find(k)!=find(k+1)) {
    33                 tot--;
    34                 ans++;
    35                 unionn(k,k+1);
    36             }
    37             if (tot==1) { cout<<ans; return 0; }
    38         }
    39     }
    40     for (int i=1; i<n; i++) {
    41         if (find((i-1)*m+1)!=find(i*m+1)) {
    42              tot--;
    43             ans+=2;
    44             unionn((i-1)*m+1,i*m+1);
    45         }
    46         if (tot==1) { cout<<ans; return 0; }
    47     }
    48     cout<<"0";
    49     return 0;
    50 }
  • 相关阅读:
    kali linux 2019.1 替换burpsuite pro 1.7.37
    java反序列化漏洞实战
    我是一个997程序员
    清晨小悟
    vue webpack配置Error
    USSD 杂记
    WingMoney APP逆向,实现自动话费充值
    保持空杯心态
    解决python在命令行中运行时导入包失败,出现错误信息 "ModuleNotFoundError: No module named ***"
    【转】Mac find 去除 “Permission denied” 信息的方法
  • 原文地址:https://www.cnblogs.com/zjzj/p/6816236.html
Copyright © 2011-2022 走看看