Closing the Farm S(并查集)

题目链接:https://www.luogu.com.cn/problem/P3144

题目大意

  • 起初有n个谷仓有m条路径,问依次关闭n个谷仓之后,农场的联通情况如何(任意两个开放的谷仓之间可以相互到达)
  • 谷仓关闭之后相应的路径也随着消失
  • 范围 1≤N,M≤3000

思路

  • 我们可以倒着思考,转换为谷仓从无到有的过程,依次添加谷仓,当联通块数为1时,表明联通,否则为分散
  • 问的是关闭之前的联通块个数,那么反过来就是开放之后联通块的个数
  • 求连通块的话,并查集是一个不错的选择

ac代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 3005;
int pre[maxn], vis[maxn], order[maxn], ans[maxn];
int n, m;
vector<int> v[maxn];
int find(int a){ // 查祖先节点
    if(a == pre[a]) return a;
    return pre[a] = find(pre[a]);
}
void merge(int a, int b){ //合并祖先节点
    int x = find(a), y = find(b);
    if(x != y) pre[x] = y;
}
int cal(){ //求连通块的个数
    int cnt = 0;
    for(int i = 1; i <= n; i ++){
        if(vis[i]) //前提是开放的谷仓
            cnt += (find(i) == i);  
    }
    return cnt;
}
int main(){
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++) {
        pre[i] = i; //初始化祖先就是自己
    }
    for(int i = 1; i <= m; i ++){//存边
        int x, y;
        scanf("%d%d", &x, &y);
        v[x].push_back(y);
        v[y].push_back(x);
    }
    for(int i = 1; i <= n; i ++){
        int x; scanf("%d", &x);
        order[i] = x; //记录关闭顺序
        vis[x] = 0; //先给他关了
    }
    for(int i = n; i >= 1; i --){ //倒着开放谷仓
        int d = order[i];
        vis[d] = 1; //开放这个谷仓
        for(auto it : v[d]){ //遍历相关的边看看需不需要合并,两个谷仓都开放才能合并
            if(vis[it]) merge(d, it);
        }
        ans[i] = cal(); //记录联通块个数
    }
    for(int i = 1; i <= n; i ++){
        if(ans[i] == 1) puts("YES");//联通块个数是1说明全联通
        else puts("NO");
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值