[HDU1232]畅通工程(并查集)

匿名 (未验证) 提交于 2019-12-03 00:29:01

给出城市的数量n以及道路的数量m,城市编号1~n,然后给出m个道路,输入1 2就是1、2之间修一条路,注意可以自身与自身连一条路。求还需要至少多少条路才能使道路畅通,即从任意一个城市出发可以到任何城市。

˼·

第一次做并查集,看博客大体知道并查集的含义。所谓并查集其实是一种数据结构,一个集合,ADT分为两个操作。首先我们开一个数组pre[], 根据名字可以知道pre[i] == j的含义是i的前一个数是j。这样我们可以根据任意一个结点找到他的根部,根据两个数的根是否相同判断这两个数是否在同一个集合之中。
让我们开始探索吧!

int find(int x) {     int r = x;     while(pre[r] != r)   //1.寻找路径的起点         r = pre[r];     int i = x, j;     while(i != r) {      //2.压缩路径         j = pre[i];         pre[i] = r;         i = j;     }     return r;             }

1.find函数的最主要的任务就是寻找路径的起点,所以用循环1来不断寻找前一个结点直到其前一个结点是自身为止。
2.压缩路径,其实这是一种优化,在本题中不压缩路径也可以过,因为数据少。压缩路径的好处是使所用结点直接指向根减少以后find时的循环1的次数。

void join(int x, int y)  {     int fx = find(x);     int fy = find(y);     if (fx != fy) {         pre[fx] = fy;      } }

join函数起的作用是将两个结点所在集合进行合并。其实看的还是所谓的根合并也是把两个集合的根之间的关系用pre数组联系起来,十分巧妙。

并查集真是一种十分巧妙的数据结构值得仔细推敲。

#include <cstdio> #include <cstring>  const int maxn = 1e3 + 10;  int pre[maxn]; int ans;  int find(int x) {          //找到路径的起点     int r = x;     while(pre[r] != r) {         r = pre[r];     }     int i = x, j;     while(i != r) {         //路径压缩         j = pre[i];         pre[i] = r;         i = j;     }     return r; }  void join(int x, int y) {     int fx = find(x);     int fy = find(y);     if (fx != fy) {         pre[fx] = fy;         ans--;     } }  int main() {     //freopen("input.txt", "r", stdin);     int n, m;     int x, y;     while(~scanf("%d", &n) && n) {         scanf("%d", &m);         ans = n - 1;       //一开始假设都不想通需要建设n-1条         for(int i = 1; i <= n; i++)             pre[i] = i;         while(m--) {             scanf("%d%d", &x, &y);             join(x, y);         }         printf("%d\n", ans);      }     return 0; }  
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!