如题,缩完点后数一下有几个入度为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 }
01-10 20:10