zoukankan      html  css  js  c++  java
  • hdu1213

    hdu1213

    ​                                                             How Many Tables

    0x00 Tags

    并查集(Disjoint Set)

    0x01 题目简介

    有n个人一起吃饭,有些人互相认识。认识的人想坐在一起,不想跟陌生人坐。例如A认识B,B认识C,那么A,B,C会坐在一张桌子上。

    给出认识的人,问需要多少张桌子?

    0x02 代码

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int maxn = 1010;
    
    int root[maxn];
    
    
    void Init()
    {
    	for (int i = 1; i < maxn; i++)
    	{
    		root[i] = i;
    	}
    }
    
    
    int Find(int x)
    {
    	return x == root[x] ? x : Find(root[x]);
    }
    
    
    void Union(int x, int y)
    {
    	x = Find(x);
    	y = Find(y);
    
    	if (x != y) root[x] = y;
    }
    
    
    
    int main()
    {
    
    	int t, n, m, x, y;
    
    	scanf("%d", &t);
    
    	while (t--)
    	{
    		scanf("%d%d", &n, &m);
    
    		Init();
    
    		for (int i = 1; i <= m; i++)
    		{
    			scanf("%d%d", &x, &y);
    			Union(x, y);
    		}
    
    		int ans = 0;
    
    		for (int i = 1; i <= n; i++)
    		{
    			if (root[i] == i)
    				ans++;
    		}
    
    		printf("%d", ans);
    	}
    
    
    
    	return 0;
    }
    

    0x03 代码优化

    路径压缩

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int maxn = 1010;
    
    int root[maxn];
    
    
    void Init()
    {
    	for (int i = 1; i < maxn; i++)
    	{
    		root[i] = i;
    	}
    }
    
    // 查找的优化---路径压缩
    int Find(int x)
    {
    	//return x == root[x] ? x : Find(root[x]);
    
    	int r = x;
    
    	while (root[r] != r)
    	{
    		r = root[r];  // 找到根结点
    	}
    
    	int i = x, j;
    	
    	while (i != r)
    	{
    		j = root[i];  // 用临时变量j记录
    		root[i] = r;  // 把路径上元素的集改为根结点
    		i = j;
    	}
    
    	return r;
    }
    
    
    void Union(int x, int y)
    {
    	x = Find(x);
    	y = Find(y);
    
    	if (x != y) root[x] = y;
    }
    
    
    
    int main()
    {
    
    	int t, n, m, x, y;
    
    	scanf("%d", &t);
    
    	while (t--)
    	{
    		scanf("%d%d", &n, &m);
    
    		Init();
    
    		for (int i = 1; i <= m; i++)
    		{
    			scanf("%d%d", &x, &y);
    			Union(x, y);
    		}
    
    		int ans = 0;
    
    		for (int i = 1; i <= n; i++)
    		{
    			if (root[i] == i)
    				ans++;
    		}
    
    		printf("%d", ans);
    	}
    
    
    
    	return 0;
    }
    

    按秩优化

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int maxn = 1010;
    
    int root[maxn];
    int Rank[maxn];
    
    
    void Init()
    {
    	for (int i = 1; i < maxn; i++)
    	{
    		root[i] = i;
    		Rank[i] = 0;  // 树的高度
    	}
    }
    
    
    int Find(int x)
    {
    	return x == root[x] ? x : Find(root[x]);
    
    }
    
    
    void Union(int x, int y)
    {
    	x = Find(x);
    	y = Find(y);
    
    	if (Rank[x] == Rank[y])
    	{
    		Rank[x] = Rank[x] + 1;
    		root[y] = x;
    	}
    	else
    	{
    		if (Rank[x] < Rank[y]) root[x] = y;
    		else root[y] = x;
    	}
    }
    
    
    
    int main()
    {
    
    	int t, n, m, x, y;
    
    	scanf("%d", &t);
    
    	while (t--)
    	{
    		scanf("%d%d", &n, &m);
    
    		Init();
    
    		for (int i = 1; i <= m; i++)
    		{
    			scanf("%d%d", &x, &y);
    			Union(x, y);
    		}
    
    		int ans = 0;
    
    		for (int i = 1; i <= n; i++)
    		{
    			if (root[i] == i)
    				ans++;
    		}
    
    		printf("%d", ans);
    	}
    
    
    	return 0;
    }
    

    备注

  • 相关阅读:
    模拟赛总结
    2018.04.06学习总结
    2018.04.06学习总结
    Java实现 LeetCode 672 灯泡开关 Ⅱ(数学思路问题)
    Java实现 LeetCode 671 二叉树中第二小的节点(遍历树)
    Java实现 LeetCode 671 二叉树中第二小的节点(遍历树)
    Java实现 LeetCode 671 二叉树中第二小的节点(遍历树)
    Java实现 LeetCode 670 最大交换(暴力)
    Java实现 LeetCode 670 最大交换(暴力)
    Java实现 LeetCode 670 最大交换(暴力)
  • 原文地址:https://www.cnblogs.com/LQ6H/p/12940542.html
Copyright © 2011-2022 走看看