1. 程式人生 > 實用技巧 >Codeforces 999E【Reachability from the Capital】(強連通縮點)

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 '\n' #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