pat 甲级 1013 Battle Over Cities

这道题的输出结果是如果那座城市失守,那么需要修复的公路数量。我们将连通的城市看出一个集合。那么需要修复的公路数量就是集合的数量-1(连通 n个点最少需要n-1)。而集合的合并以及确定集合的数量,可以使用并查集。

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;
const int N=1010,M=500010;//N<1000,因为M是边,包含N个点最多的边的图为完全图即M<(N*(N-1)/2)
int n,m,k;
int p[N];//集合,p[i]表示i的祖宗(根节点)
struct Edge{
    int a,b;
}e[M];//边,a,b为边的两个顶点
int find(int x){//压缩路径,返回x的祖宗。
    if(x!=p[x]) p[x]=find(p[x]);
        return p[x];
}
int main()
{
    cin>>n>>m>>k;
    for(int i=0;i<m;i++){//读入m条边
        cin>>e[i].a>>e[i].b;
    }
    while(k--){
        int x;
        cin>>x;
        int cnt=n-1;//去掉被占领的城市,共有n-1个城市,故有n-1个集合。
        for(int i=1;i<=n;i++) p[i]=i;//并查集的初始化,一开始每个集合只有自己本身,i的祖宗即本身,故p[i]=i;
        for(int i=0;i<m;i++){
            int a=e[i].a,b=e[i].b;
            if(a!=x&&b!=x){//该边与被占领的城市无关,则将两个顶点所属的集合合并
                int pa=find(a),pb=find(b);//查找两个顶点的祖宗。
                if(pa!=pb){//祖宗不相同
                    p[pa]=pb;//令(a的祖宗pa)的祖宗为pb,即两个集合合并
                    cnt--;//两集合合并,故集合数量-1
                }
            }
        }
        cout<<cnt-1<<endl;//剩下cnt个集合,需要cnt-1条路修复
    }
    return 0;
}

并查集的路径压缩:路径为压缩之前如图1,我们调用find(4),因为(4!=p[4]) 执行p[4]=find(p[4]);递归调用直到p[x]==x,由于p[1]=1,故返回1。则p[4]=1;此时变成图2,最终会变成图3。则下次查询祖宗时,效率会大大提升。

                                图1

                                图2

                                图3

  • 16
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值