如题,缩完点后数一下有几个入度为1的scc,+1再/2即可。
教训:加一个cntf处理重边!否则重边会被认为是同一条。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 8 struct stack{ 9 vector<int> v; 10 void push(int x){v.push_back(x);} 11 void pop(){v.pop_back();} 12 int size(){return v.size();} 13 bool empty(){return v.empty();} 14 int top(){return v[v.size()-1];} 15 }s; 16 17 const int Maxn = 5010; 18 19 vector<int> g[Maxn],scc[Maxn]; 20 int dfn[Maxn],low[Maxn],inscc[Maxn],ins[Maxn]; 21 int inv[Maxn]; 22 int n,m,cntv,cntscc,cnt; 23 24 void tarjan(int x,int fa){ 25 low[x] = dfn[x] = ++cntv,ins[x] = 1; 26 s.push(x);int cntf = 0; 27 for(int i = 0;i < g[x].size();i++){ 28 int u = g[x][i]; 29 if(u == fa&&!cntf){cntf++;continue;} 30 if(!dfn[u])tarjan(u,x),low[x] = min(low[x],low[u]); 31 else low[x] = min(low[x],dfn[u]); 32 } 33 if(dfn[x] == low[x]){ 34 int y = -1;cntscc++; 35 while(!s.empty()&&y^x){ 36 y = s.top();s.pop(); 37 ins[y] = 0,inscc[y] = cntscc; 38 scc[cntscc].push_back(y); 39 } 40 } 41 } 42 43 int main(){ 44 scanf("%d%d",&n,&m); 45 for(int i = 1;i <= m;i++){ 46 int u,v; 47 scanf("%d%d",&u,&v); 48 g[u].push_back(v); 49 g[v].push_back(u); 50 } 51 tarjan(1,-1); 52 for(int i = 1;i <= n;i++) 53 for(int j = 0;j < g[i].size();j++) 54 if(inscc[i]^inscc[g[i][j]])inv[inscc[g[i][j]]]++; 55 for(int i = 1;i <= cntscc;i++)if(inv[i] == 1)cnt++; 56 cout << (cnt+1)/2; 57 return 0; 58 }