首页 > 试题广场 >

畅通工程

[编程题]畅通工程
  • 热度指数:12694 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 64M,其他语言128M
  • 算法知识视频讲解
    某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?

输入描述:
    测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。 
    注意:两个城市之间可以有多条道路相通,也就是说
    3 3
    1 2
    1 2
    2 1
    这种输入也是合法的
    当N为0时,输入结束,该用例不被处理。


输出描述:
    对每个测试用例,在1行里输出最少还需要建设的道路数目。
示例1

输入

4 2
1 3
4 3
3 3
1 2
1 3
2 3
5 2
1 2
3 5
999 0
0

输出

1
0
2
998
考察的应为并查集的内容,彼此连通的城镇是在一个集合中,根据输入的每条道路,将城镇Union,最后数一下集合的个数
#include<iostream>
(720)#include<cstdio>

using namespace std;

const int MaxN = 1000;

int father[MaxN];
int height[MaxN];

void Initial(int n){
    for(int i=1; i<=n; i++){
        father[i] = i;
        height[i] = 0;
    }
}

int Find(int x){
    if(x!=father[x]){
        father[x] = Find(father[x]);
    }
    return father[x];
}

void Union(int x,int y){
    x = Find(x);
    y = Find(y);
    if(x!=y){
        if(height[x]>height[y]){
            father[y] = x;
        }
        else if(height[x]<height[y]){
            father[x] = y;
        }
        else{
            father[y] = x;
            height[x]++;
        }
    }
    return;
}

int main(){
    int N,M;
    while(cin>>N){
        if(N==0){
            break;
        }
        cin>>M;
        Initial(N);
        for(int i=0; i<M; i++){
            int a,b;
            cin>>a>>b;
            Union(a,b);
        }
        int answer = -1;
        for(int i=1; i<=N; i++){
            if(i==Find(i)){
                answer++;
            }
        }
        cout<<answer<<endl;
    }
    return 0;
}

发表于 2020-02-22 15:36:29 回复(3)
//并查集
//求连通分量数

#include<iostream>

using namespace std;

const int MAX_N = 1001;

int father[MAX_N];
int height[MAX_N];

void Init(int n){
    // 各结点的父结点初始为自己
    // 求连通分量数,即求父结点是自己的结点个数
    for(int i = 0; i <= n; i++){
        father[i] = i;
        height[i] = 0;
    }
}

// 查,查找父结点
int Find(int x){
    // 路径压缩,直接链接到根结点下,使树尽可能矮
    if(x != father[x]){
        father[x] = Find(father[x]);
    }
    return father[x];
}

// 并
void Union(int a, int b){
    // 查找两个结点的根节点
    a = Find(a);
    b = Find(b);
    
    // 根节点不同,进行合并
    if(a != b){
        // 合并时,把矮的合并到高的,树高不变
        if(height[a] < height[b]){
            father[a] = b;
        }
        else if(height[a] > height[b]){
            father[b] = a;
        }
        else{
            father[a] = b;
            height[b]++;
        }
    }
}

int main(){
    // n 表示城镇数, m 表示道路数
    int n, m;
    while(cin >> n){
        if(n == 0)
            break;
        cin >> m;
        // 初始化
        Init(n);
        // 输入道路
        while(m--){
            int x, y;
            cin >> x >> y;
            Union(x, y);
        }
        // 经过合并后,连通分量数=父结点是自己的结点数
        // 要修建的道路数 = 连通分量数 - 1
        // ans 初始为 -1,不是 0
        int ans = -1;
        for(int i = 1; i <= n; i++){
            if(father[i] == i){
                ans++;
            }
        }
        cout << ans << endl;
    }
    return 0;
}

发表于 2022-02-26 22:07:52 回复(0)
#include<iostream>
using namespace std;

const int maxn = 1000;
int father[maxn];
int height[maxn];

void Initial(int n)
{
	for (int i = 0; i <= n; i++)
	{
		father[i] = i;
		height[i] = 0;
	}
}
int Find(int x)
{
	if (x != father[x])//当元素不是集合根部时
		father[x] = Find(father[x]);//路劲压缩,直接指向根节点,使树高最小
	return father[x];
}
void Union(int x, int y)
{
	x = Find(x);//先找到集合根部
	y = Find(y);
	if (x != y)//不是同一个集合根部,即不是同一个集合
	{//矮树往高树合并,提高查询效率
		if (height[x] < height[y])
			father[x] = y;
		else if (height[x] > height[y])
			father[y] = x;
		else//一样高
		{
			father[y] = x;
			height[x]++;
		}
	}
}
int main()
{
	int N, M;
	while (cin>>N && N != 0 && cin>>M)
	{
		Initial(N);
		while (M--)
		{
			int x, y;
			cin >> x >> y;
			Union(x, y);
		}
		int ans = -1;//N个城镇最少N-1条路就能连通了
		for (int i = 1; i <= N; i++)
			if (Find(i) == i)//检查集合数量,即没连通的城镇数量
				ans++;
		cout << ans << endl;
	}
	return 0;
}

并查集
编辑于 2020-06-27 10:51:29 回复(0)
#include<iostream>
(720)#include<bits/stdc++.h>
#define max 1000
using namespace std;

int father[max];
int length[max];

int find(int x){			//找节点x的根节点(如果是单个节点,就返回自己) 
	while(father[x]!=-1){
		x=father[x];
	}
	return x;
}


//思想是节点x和y联通,只需要将他们的根节点相连,也相当于他们连通 
void union_node(int x,int y){//此函数的目的是将x和y所在的树进行合并,并尽量使高度最小,减少find函数的查找次数 
	x = find(x);			
	y = find(y);
	if(x!=y){				//如果x和y节点的根节点相同,说明他们在同一条链中,不操作。 
		if(length[x]==length[y]){	//高度如果相等,选取任意一根节点作为另一节点的父节点 
			father[x]=y;
			length[y]++;			//被选取的根节点高度加1 
		}else{						
			length[x]>length[y]?father[y]=x:father[x]=y;//不相等,选取高度大的作为父节点 
		}
	}
	
}
int main(){
	int N,M,x,y;
	while(cin>>N&&N!=0){
		cin>>M;
		memset(father,-1,sizeof(father));
		memset(length,0,sizeof(length));
		while(M--){
			cin>>x>>y;
			union_node(x,y);
		}
		int ans=-1;					//父节点为1的节点有树的根节点和不连通的单个节点,所以设为-1去除根节点 
		for(int i=1;i<=N;i++){
			if(father[i]==-1) ans++;
		}
		cout<<ans<<endl;
	}
	return 0;
}

编辑于 2020-03-13 19:30:27 回复(0)
Java 解法, 使用并查集数据结构
import java.util.Scanner;
import java.util.TreeSet;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()){
            int townNum = scanner.nextInt();
            int pathNum = scanner.nextInt();
            UnionFind unionFind = new UnionFind(townNum+1);
            for (int i = 0; i < pathNum; i++) {
                int town1 = scanner.nextInt();
                int town2 = scanner.nextInt();
                unionFind.union(town1,town2);
            }
            TreeSet<Integer> set = new TreeSet<>();
            for (int i = 1; i <=townNum; i++) {
                set.add(unionFind.find(i));
            }
            System.out.println(set.size()-1);
        }
    }
    public static class UnionFind {
        private int[] id;

        public UnionFind(int N) {
            id = new int[N];
            for(int i = 0; i < N; i++) id[i] = i;
        }
        
        public int find(int p) {
            return id[p];
        }
        
        public void union(int p, int q){
            int pRoot = find(p);
            int qRoot = find(q);
            if(pRoot == qRoot) return;
            for(int i = 0; i < id.length; i++)
                if(id[i] == pRoot)  id[i] = qRoot;
        }
    }
}


发表于 2020-03-07 10:48:25 回复(0)
//总的最少边数为n-1,统计现有边,有一条减少一条(忽略重复边,已连通则不计),剩余的即为还需修建的边数
#include <iostream>
using namespace std;
#define N 1000
int tree[N];
int findroot(int x)
{
if (-1 == tree[x]) return x;
tree[x] = findroot(tree[x]);
return tree[x];
}

int main()
{
int n = 0, m = 0;
while (cin>>n>>m && 0 != n)
{
int a = 0, b = 0;
for (int i = 0; i < N; ++i) tree[i] = -1;
while (m--)
{
cin >> a >> b;
int ta = findroot(a);
int tb = findroot(b);
if (ta != tb) { tree[tb] = ta; --n; }
}
cout << n - 1 << endl;
}
return 0;
}

编辑于 2020-02-19 13:14:10 回复(0)
#include <iostream>
#include <cstring>
using namespace std;
#include <algorithm>
#define N 1001

int finds(int p[],int x){
    while(p[x]>0){
        x = p[x];
    }
    return x;
}

int main(){
    int n,m; ///n个城 m条路
    int p[N];
    int i,a,b;
    while(cin >> n >> m){
        if(n==0) break;
        memset(p,0,sizeof(p));
        for(i=0;i<m;++i){
            cin >> a >> b;
            int x = finds(p,a);
            int y = finds(p,b);
            if(x!=y){
                p[x] = y;
            }
        }
        int ans = -1;
        for(i=1;i<=n;i++){
            if(p[i]==0){
                ++ans;///找多少个非连通分量
            }
        }
        cout << ans << endl;
    }
    return 0;
}

发表于 2019-03-19 17:17:49 回复(0)
  • 本题求连通分量:
#include<iostream>
#include<vector>
#include<utility>
#include<deque>
#include<map>
using namespace std;
vector<pair<int,int>> roads;
map<int,bool> m;//<城市,visited>
void bfs(int i){
    deque<int> d;
    d.push_back(i);
    m[i]=true;
    while(!d.empty()){
        int j = d.front();
        d.pop_front();
        for(pair<int,int> road:roads){
            if(road.first==j) {
                if(!m[road.second]){
                    m[road.second] = true;
                    d.push_back(road.second);
                }
            }else{
                if(!m[road.first]){
                    m[road.first] = true;
                    d.push_back(road.first);
                }
            }
        }
    }
}
int main(){
    int n;
    while(cin>>n&&n!=0){
        int mm;
        cin>>mm;
        
        for(int i=1;i<=n;i++){
            m[i] = false;
        }
        for(int i=0;i<mm;i++){
            int a,b;
            cin>>a>>b;
            pair<int,int> road = make_pair(a,b);
            roads.push_back(road);
        }
        int cons=0;
        for(int i=1;i<=n;i++){
            if(!m[i]){
                bfs(i);
                cons++;
            }
        }
        cout<<cons-1<<endl;
    }
    
    return 0;
}

编辑于 2019-01-21 18:47:26 回复(0)
和最小生成树思想差不多,找到这些城镇节点能构成多少颗树,就需要造树的数量-1条道路。
找出边的结点的根是否一样,不一样表示这两个数可以通过这条边联结为一颗树。
while True:
    try:
        def findRoot(b):    #找树根
            global roads
            if roads[b] == 0:                #树根为0表示自己为根
                return b
            else:
                temp = findRoot(roads[b])
                roads[b] = temp
                return temp
        town,roadNum = list(map(int,input().split()))
        roads = [0 for i in range(town+1)]   #一开始每个树根为0,0下标我没用
        for i in range(roadNum):
            tempInput = list(map(int, input().split()))
            a = findRoot(tempInput[0])       #找出两个新来边的结点的根是否相同
            b = findRoot(tempInput[1])
            if a != b:                       #如果根不一样,这条路把他们连接到一起,两棵树缩成一棵树
                roads[a] = b
        print(roads.count(0)-2)   #0的数量减去1(下标为0的值为0)得到树的棵数,再减一得到需要造的路
    except Exception:
        break
编辑于 2018-09-25 15:32:38 回复(0)
import java.util.Scanner;
public class Main{
    static int[] parent;
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        while(in.hasNext()){
            int N = in.nextInt();
            int M = in.nextInt();
            if(N==0)
                break;
            parent = new int[N+1];
            for(int i=0;i<=N;i++)
                parent[i]=-1;
            for(int i=0;i<M;i++){
                int left = in.nextInt();
                int right = in.nextInt();
                int leftParent = findroot(left);
                int rightParent = findroot(right);
                if(leftParent!=rightParent)
                    parent[rightParent] = leftParent;
                
            }
            int ans = 0;
            for(int i=1;i<=N;i++){
                if(parent[i]==-1)
                    ans++;
            }
            System.out.println(ans-1);
        }
    }
    public static int findroot(int index){
        if(parent[index]==-1)
            return index;
        int tmp = findroot(parent[index]);
        parent[index] = tmp;
        return tmp;
    }
}

发表于 2018-02-14 14:41:56 回复(0)
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
 
int find(const vector<bool> & v) {
    for(int i = 0; i<v.size(); i++) {
        if(v[i] == false) {
            return i;
        }
    }
    return -1;
}
 
int main() {
    //freopen("t.txt", "r", stdin);
 
    int N;
    while(cin>>N, N) {
        int M;
        cin>>M;
        vector<vector<bool>> mat(N, vector<bool>(N));
        for(int i = 0; i<M; i++) {
            int a, b;
            cin>>a>>b;
            a--,b--;
            mat[a][b] = true;
            mat[b][a] = true;
        }
 
        vector<bool> traversed(N, false);
        int start = 0;
        int res = -1;
        do {
            res++;
            queue<int> q;
            q.push(start);
            traversed[start] = true;
            while(!q.empty()) {
                int f = q.front(); q.pop();
                for(int link = 0; link < N; link++) {
                    if(f == link) continue;
                    if(mat[f][link] && traversed[link]==false) {
                        q.push(link);
                        traversed[link] = true;
                    }
                }
            }
        } while((start=find(traversed)) != -1);
        cout<<res<<endl;
    }
}

发表于 2017-02-25 10:22:45 回复(0)
并查集。。
#include<iostream>
using namespace std;
int FindRoot(int a,int Tree[]){
    if(Tree[a]==-1) return a;
    else{
        int tmp=FindRoot(Tree[a],Tree);
        Tree[a]=tmp;
        return tmp;
    }
}
int main(){
    int n,m;
    int Tree[1001];
    while(cin>>n>>m&&n!=0){
        int a,b;
        for(int i=1;i<=n;i++)
            Tree[i]=-1;
        for(int i=0;i<m;i++){
            cin>>a>>b;
            a=FindRoot(a,Tree);
            b=FindRoot(b,Tree);
            if(a!=b)
                Tree[b]=a;
        }
        int ans=0;
        for(int i=1;i<=n;i++)
            if(Tree[i]==-1) ans++;
        cout<<ans-1<<endl;
    }
    return 0;
} 

发表于 2018-01-19 17:18:03 回复(1)
题目等于是在问有多少个连通分量,考察的是并查集的基本应用。
#include <stdio.h>
#define N 1000

int parent[N];//parent[i]表示节点i的双亲是谁, -1表示不存在

int FindRoot(int x)//寻找x所在的树的根节点
{
    if(parent[x]==-1) return x;
    else//递归调用
    {
        int ret=FindRoot(parent[x]);
        parent[x]=ret;//路径压缩
        return ret;
    }
}

int main()
{
    int m, n;
    while(scanf("%d", &n)!=EOF)
    {
        if(n<=0) break;
        scanf("%d", &m);
        for(int i=1; i<=n; i++) parent[i]=-1;//一开始全是根
        while(m--)
        {
            int x, y;
            scanf("%d %d", &x, &y);
            x=FindRoot(x);
            y=FindRoot(y);
            if(x!=y) parent[y]=x;//不在同一棵树那就合并
        }
        int count=0;//统计一下根节点数量
        for(int i=1; i<=n; i++)
        {
            if(parent[i]==-1) count++;
        }
        printf("%d\n", count-1);
    }
    return 0;
}

编辑于 2018-03-06 15:47:04 回复(0)
//老哥们一看就是用的并查集
//我换种解法:dfs
#include<iostream>
using namespace std;
const int maxn=1001,INF=1000000000;
int n,m,g[maxn][maxn],d[maxn],vis[maxn];
void dfs(int s)
{
    vis[s]=1;
    for(int i=1;i<=n;i++)
    {
        if(vis[i]==0&&g[s][i]!=INF)
            dfs(i);
    }
}
int main()
{
    int a,b,ans;
    while(cin>>n&&n)
    {
        cin>>m;
        ans=0;
        fill(vis,vis+maxn,0);
        fill(g[0],g[0]+maxn*maxn,INF);
        for(int i=0;i<m;i++)
        {
            cin>>a>>b;
            g[a][b]=g[b][a]=1;
        }
        for(int i=1;i<=n;i++)
        {
            if(vis[i]==0)
            {
                ans++;
                dfs(i);
            }
        }
        cout<<ans-1<<endl;
    }
    return 0;
}

发表于 2018-03-18 09:54:52 回复(1)
#include<bits/stdc++.h>
using namespace std;

const int Max=1000;
int father[Max];
int height[Max];

void Initial(int n) {
    for(int i=1; i<=n; i++) {
        father[i]=i;
        height[i]=0;
    }
    return ;
}

int Find(int x) {
    if(x!=father[x]) {
        father[x]=Find(father[x]);
    }
    return father[x];
}

void Union(int a,int b) {
    int x=Find(a);
    int y=Find(b);
    if(x!=y){
        if(height[x]>height[y]){
            father[y]=x;
        }
        else if(height[x]<height[y]){
            father[x]=y;
        }
        else{
            father[y]=x;
            height[x]++;
        }
    }
    return ;
}

int main() {
    int n,m;
    while(cin>>n>>m) {
        if(n==0){
            break;
        }
        Initial(n);
        for(int i=0; i<m; i++) {
            int a,b;
            cin>>a>>b;
            Union(a,b);
        }
        int answer=-1;
        for(int i=1;i<=n;i++){
            if(i==Find(i)){
                answer++;
            }
        }
        cout<<answer<<endl;
    }
    return 0;
}
发表于 2022-10-13 14:37:18 回复(1)
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        //畅通工程,自行理解再写一遍
        Scanner in = new Scanner(System.in);
        while (in.hasNext()) {
            int N = in.nextInt();//城镇数量
            int M = in.nextInt();//路径数量
            UnionFindSet uSet = new UnionFindSet(N, 1000);
            for (int i = 0; i < M; i++) {
                int x = in.nextInt();
                int y = in.nextInt();
                uSet.Union(x, y);

            }
            //初始化道路数为-1
            int count = -1;
            for (int i = 1; i <= N; i++) {
                //看看有多少个集合,就要加多少条道路-1,但因为count已经初始化为-1,所以不用再-1
                if (uSet.father[i] == i) {
                    count++;
                }
            }
            System.out.println(count);
        }
    }

    public static class UnionFindSet {
        //初始化两个数组
        //father表示父结点,height并查集节点高度
        //初始化,将所有城镇看成独立的个体,没有父结点,所存的数为本身的下标
        private int father[];
        private int height[];
        //构造函数初始化,这里m非题目要求,这里只是给数组申请存储空间,静态输入即可
        public UnionFindSet(int n, int m) {
            this.father = new int[m];
            this.height = new int[m];
            for (int i = 1; i <= n; i++) {
                father[i] = i;//从下标1开始
                height[i] = 0;
            }
        }

        //递归查找根节点
        int Find(int x) {
            if (x != father[x]) {
                return Find(father[x]);
            } else {
                return father[x];
            }
        }

        //union
        public void Union(int x, int y) {
            //首先需要找到它们两个的根节点
            x = Find(x);
            y = Find(y);
            if (x != y) {
                //如果根节点不相等,就合并
                if (height[x] < height[y]) {
                    father[x] = y;//把高度低的合并到高度高的树上面
                } else if (height[x] > height[y]) {
                    father[y] = x;
                } else {
                    father[x] = y;//高度相等就统一合并
                    height[y]++;//再给合并的树加高度
                }
            }//完成union
        }
    }
}
发表于 2024-03-21 11:29:50 回复(0)
#include<stdio.h>

int father[1000];
void Init(int a[],int n){
     for(int i=0;i<n;i++){
        a[i] = i;
     }
}
int FindFather(int n){
    if(father[n]==n) return n;
    else {
        father[n] = FindFather(father[n]);
        return father[n];
    }
}
void Union(int a,int b){
    int root1 = FindFather(a);
    int root2 = FindFather(b);
    father[root1] = root2;
}
int main(){
    int N;int M;
    while(scanf("%d%d",&N,&M)!=EOF){
        if(N==0) return 0;
        Init(father,1000);
        int count = 0;
        for(int i=0;i<M;i++){
            int a,b;
            scanf("%d%d",&a,&b);
            Union(a,b);
        }
        for(int i=1;i<N;i++){
            int r1 = FindFather(i);
            int r2 = FindFather(i+1);
            if(r1!=r2) {Union(r1, r2); count++;}
        }
        printf("%d\n",count);
    }
}

编辑于 2024-03-12 21:15:02 回复(0)
#include <iostream>
#include <type_traits>
#include <vector>
using namespace std;

const int MAXN = 1000;

vector<int>father(MAXN);                        //父亲结点
vector<int>height(MAXN);                        //结点高度

void Initial(int n) {                           //初始化
    for (int i = 0; i <= n; i++) {
        father[i] = i;                          //每个结点的父亲为自己
        height[i] = 0;                          //每个结点的高度为0
    }
}

int Find(int x) {                               //查找根结点
    if (x != father[x]) {                       //路径压缩
        father[x] = Find(father[x]);
    }
    return father[x];
}

void Union(int x, int y) {                      //合并集合
    x = Find(x);
    y = Find(y);
    if (x != y) {                               //矮树作为高树的子树
        if (height[x] < height[y]) {
            father[x] = y;
        } else if (height[y] < height[x]) {
            father[y] = x;
        } else {
            father[y] = x;
            height[x]++;
        }
    }
}

int main() {
    int n, m;
    while (cin >> n && n != 0) {
        cin >> m;
        Initial(n);                             //初始化
        while (m--) {
            int x, y;
            cin >> x >> y;
            Union(x, y);                        //合并集合
        }
        int answer = -1;
        for (int i = 1; i <= n; i++) {
            if (Find(i) == i) {                 //集合数目
                answer++;
            }
        }
        cout << answer << endl;
    }
    return 0;
}

发表于 2024-02-20 23:02:19 回复(0)
没怎么写过并查集,很粗糙
#include "iostream"

#include <vector>
#include <algorithm>

using namespace std;

vector<int> parent;


int find(int a){
    if(parent[a]== -2){
        parent[a] = -1; // 加入后初始化
    }
    if(parent[a]!=-1){
        a = find(parent[a]);
    }

    return a;
}



void to_union(int a,int b){
    int x = find(a);
    int y = find(b);
    if(x != y){
        parent[y] = x;
    }
}

int main(){
    int size,num;
    while(cin >> size>>num){
        if(num==0) {
            cout << size - 1 << endl;
            continue;
        }
        parent.resize(size,-2);
        for(int i=0; i < num;++i){
            int a,b;
            cin >> a >> b;
            to_union(a-1,b-1);
        }
        // 然后找parent中不同的个数
        sort(parent.begin(),parent.end());
        int count_set = 0;
        int count_num = 0;
        for (int i = 0; i < size; ++i) {
//            cout << parent[i] << " ";
            if(parent[i]==-1) {count_num++; count_set++; }
            if(parent[i]>=0) count_num++;
        }
//        cout << endl;
        cout << size-count_num+count_set-1 << endl;
    }

}


发表于 2023-03-05 20:01:12 回复(0)
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int N;
        while (scanner.hasNext() && (N = scanner.nextInt()) != 0) {
            int M = scanner.nextInt();
            UnionFindSet ufs = new UnionFindSet(N, 1000);
            for (int i = 0; i < M; i++) {
                ufs.union(scanner.nextInt(), scanner.nextInt());
            }
            int count = -1;
            for (int i = 1; i <= N; i++) {
                if (ufs.father[i] == i) {
                    count++;
                }
            }
            System.out.println(count);
        }
    }
    public static class UnionFindSet {
        private int father[];
        private int height[];
        public UnionFindSet(int n, int max) {
            this.father = new int[max];
            this.height = new int[max];
            for (int i = 1; i <= n; i++) {
                this.father[i] = i;
                this.height[i] = 0;
            }
        }

        int find(int x) {
            if (x != father[x]) {
                father[x] = find(father[x]);
            }
            return father[x];
        }

        void union(int x, int y) {
            x = find(x);
            y = find(y);
            if (x != y) {
                if (height[x] < height[y]) {
                    father[x] = y;
                } else if (height[x] > height[y]) {
                    father[y] = x;
                } else {
                    father[y] = x;
                    height[x]++;
                }
            }
        }
    }
}

发表于 2023-02-11 19:21:41 回复(0)

问题信息

难度:
61条回答 8627浏览

热门推荐

通过挑战的用户

查看代码