嘛,首先把图缩点一下之后就很好搞了
考虑一下,什么情况下可以使得加边最少,并且s可以把所有点遍历到?
很显然,对于一个入度不为0的点,一定有前继节点....
于是乎,我们只要找到不满足有前继节点的节点就好了
详细的过程看代码...
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define MAXN 5005 using namespace std; int n,m,tot,tot2,dx,tx; int s,p,ed; int sum; int in[MAXN]; int h[MAXN],h2[MAXN],low[MAXN],dfn[MAXN],belong[MAXN]; bool vis[MAXN]; stack<int>q; struct node{ int from,to,next; }e[MAXN<<1],e2[MAXN<<1]; void init(){ tot = tot2 = dx = tx = sum = 0; memset(h,-1,sizeof(h)); memset(h2,-1,sizeof(h2)); memset(dfn,0,sizeof(dfn)); memset(in,0,sizeof(in)); memset(low,0,sizeof(low)); memset(vis,false,sizeof(vis)); } void add(int x,int y){ tot++; e[tot].from = x; e[tot].to = y; e[tot].next = h[x]; h[x] = tot; } void add2(int x,int y){ tot2++; e2[tot2].from = x; e2[tot2].to = y; e2[tot2].next = h2[x]; h2[x] = tot2; } int tarjan(int now){ dx++; low[now] = dfn[now] = dx; q.push(now),vis[now] = true; for(int i = h[now];i != (-1);i = e[i].next){ if(!dfn[e[i].to]){ tarjan(e[i].to); low[now] = min(low[now] , low[e[i].to]); } else if(vis[e[i].to]){ low[now] = min(low[now] , dfn[e[i].to]); } } if(dfn[now]==low[now]){ int u; tx++; do{ u = q.top(); belong[u] = tx; q.pop(); vis[u] = false; }while(u!=now); } } void solve(){ for(int i = 1;i<=tx;i++){ if(!in[i]&&i != belong[s]){ sum++; in[i]++; } } cout<<sum<<endl; } int main(){ init(); cin>>n>>m>>s; for(int i = 1;i<=m;i++){ int x,y;cin>>x>>y; add(x,y); } for(int i = 1;i<=n;i++) if(!dfn[i])tarjan(i); for(int i = 1;i<=m;i++){ if(belong[e[i].from] == belong[e[i].to])continue; add2(belong[e[i].from] , belong[e[i].to]); in[belong[e[i].to]]++; } solve(); }