错题-公路修建

公路修建

问题描述

你现在是城市的主人
现在有 n 个村庄,要修建 m 条路,每修建一条路,道路是双向的,输出至少还需要修建几条,可以让所有村庄互相可达。
一开始路为 0 条

数据保证有解

输入格式

第一行两个整数 n,m , 0≤n,m≤105 接下来有 m 行,每行 a,b 代表修建了一条从第 a 个村庄,到第 b 个村庄的路。 1≤a,bn
ab 可能相同。

输出格式

一共 m 行,第 i 个数代表已经修建了前 i 条路时,最少还需要修建几条,可以让所有村庄互相可达。

样例输入

5 5
1 1
1 2
2 3
4 4
1 2

样例输出

4
3
2
2
2

并查集!!使用路径压缩

int find(ll x) //寻找所在类的根
{
     return bingchaji[x] == x ? x : bingchaji[x] = find(bingchaji[x]);//第二个是返回赋的值
}

后面那项可以把路上经过的 bingchaji[i] 的值全部赋成祖先,之后查询就快了。

算法思想:每次增加一条路的时候,判断是不是把两个类簇合并成一个类簇,如果是就可以减少修一条路

在判断这个图还有几个类簇也用上面的方法,在输入路的时候顺便判断合并了几个类簇。

!!!不要企图用set容器来判断类簇的数量,像这个题目,首先会超时,其次在两个类合成的时候,只有一个根会让他的并查集的值等于另一个,但是这个根的其他儿子的并查集的值还是这个根的值啊,都没有变成另外一个根啊,那不就放到set的时候就出错了吗?!

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

ll bingchaji[10000000] = {0};
int find(ll x) //寻找所在类的根
{
     return bingchaji[x] == x ? x : bingchaji[x] = find(bingchaji[x]);//第二个是返回赋的值
}
int main()
{
     ll n, m;
     cin >> n >> m;
     for (ll i = 1; i <= n; i++) //对并查集初始化
     {
          bingchaji[i] = i;
     }
     n--;//最多只需要修n - 1条路
     for (ll i = 1; i <= m; i++)
     {
          ll a, b;
          cin >> a >> b;
          ll k = find(a);
          ll kk = find(b);
          if (kk != k)
          {
               n--;
               bingchaji[kk] = k; //更新并查集
               //注意这里要把一个类的**根**附属到另一个类的**根**下,如果只把新修的这条路的一个节点归到另一个类的根下面,则这个节点所属的类的其他节点不知道已经属于另一个类了
          }
          cout << n << endl;
     }
     return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值