给出城市的数量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; }  文章来源: [HDU1232]畅通工程(并查集)