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; }