Codeforces 999E【Reachability from the Capital】(强连通缩点)

CF2000分

题意:给你n个点m条单向边和根节点root,问root要能成功访问所有点所需要添加的边数。

题解:

1.(官方题解)显然强联通缩点。缩点完后对每个点的入度进行统计,如果入度是0就++ans

2.(我的解法)强连通缩点完后,因为点数和边数最多就5000个点,所以可以O(n^2)暴力跑dfs求出每个点可以到达的点有哪些,用vector记录。然后因为包含关系,所以我们对vector按大小从大到小排序。看每个点是否被访问过,如果没被访问过就把vector里的所有点都访问一下,时间复杂度大概是O(n^2)。比官方题解慢了很多但是就这个题而言可以过

我就附上我自己的AC代码吧

#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '
'
#define eps 0.000000001
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int maxn=5e3+5;
int tot,head[maxn];
struct E{
    int to,next;
}edge[maxn<<1];
void add(int u,int v){
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
int n,m,root,u[maxn],v[maxn],id[maxn],low[maxn],dfn[maxn],vis[maxn],tott,cnt;
stack<int> s;
void tarjan(int x){
    low[x]=dfn[x]=++tott;
    s.push(x);vis[x]=1;
    for(int i=head[x];i!=-1;i=edge[i].next){
        int v=edge[i].to;
        if(!dfn[v]){
            tarjan(v);
            low[x]=min(low[x],low[v]);
        }
        else if(vis[v]){
            low[x]=min(low[x],dfn[v]);
        }
    }
    if(low[x]==dfn[x]){
        cnt++;
        while(1){
            int now=s.top();
            s.pop();
            vis[now]=0;
            id[now]=cnt;
            if(now==x) break;
        }
    }
}
vector<vector<int> > vec(maxn);
void bfs(int x){
    set<int> s;
    queue<int> q;q.push(x);
    while(!q.empty()){
        int now=q.front();q.pop();
        s.insert(now);vec[x].push_back(now);
        for(int i=head[now];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(s.count(v)) continue;
            s.insert(v);
            q.push(v); 
        }
    }    
}
bool cmp(vector<int>&a,vector<int>&b){
    return a.size()>b.size();
}
int viss[maxn];
int main(){
    scanf("%d%d%d",&n,&m,&root);mem(head,-1);tott=cnt=0;
    rep(i,1,m){
        scanf("%d%d",&u[i],&v[i]);
        add(u[i],v[i]);
    }
    for(int i=1;i<=n;i++){
        if(!dfn[i]) tarjan(i);
    }
    mem(head,-1);tot=0;
    for(int i=1;i<=m;i++){
        int uu=id[u[i]],vv=id[v[i]];
        if(uu==vv) continue;
        add(uu,vv);
    }
    root=id[root];
    for(int i=1;i<=cnt;i++){
        bfs(i);
    }
    int ans=0;
    for(int i=0;i<vec[root].size();i++){
        viss[vec[root][i]]=1;
    }
    sort(vec.begin(),vec.end(),cmp);
    for(int i=0;i<cnt;i++){
        if(viss[vec[i][0]]) continue;
        ++ans;
        for(auto it:vec[i]) viss[it]=1;
    }
    cout<<ans<<endl;
}
View Code
原文地址:https://www.cnblogs.com/Anonytt/p/13854288.html