本文搬运自本人初中博客园博客,若图片加载不出来,可到原文查看:https://www.cnblogs.com/zhangtingxi/p/15615609.html

题目链接

首先,环内的节点必然可以至少存在两条路径到达,所以我们不用考虑环内的节点,可以先对无向图缩点。

剩下的节点必然构成一棵树,我们只需要将叶子节点两两配对。因为这样其上面的所有父亲节点都可以通过它下面的叶子节点形成环。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// Problem: #10098. 「一本通 3.6 例 1」分离的路径
// Contest: LibreOJ
// URL: https://loj.ac/p/10098
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define M 10010
//#define mo
#define N 5010
struct node
{
int x, y, n;
}d[M*2];
int n, m, i, j, k;
int h[N], f[N], c[N], dep[N], rd[N];
int lf, u, v;

void cun(int x, int y)
{
d[++k].x=x; d[k].y=y;
d[k].n=h[x]; h[x]=k;
}

int fa(int x)
{
if(f[x]==x) return x;
return f[x]=fa(f[x]);
}

void dfs(int x)
{
for(int g=h[x]; g; g=d[g].n)
{
if(c[g]) continue;
c[((g-1)^1)+1]=c[((g-1)^1)+1]=1;
int y=d[g].y;
if(!dep[y])
{
dep[y]=dep[x]+1;
dfs(y);
}
if(dep[fa(y)]>0)
{
if(dep[f[y]]<dep[fa(x)]) f[f[x]]=f[y];
else f[f[y]]=f[x];
}
}
dep[x]=-1;
}

signed main()
{
// freopen("tiaoshi.in", "r", stdin);
// freopen("tiaoshi.out", "w", stdout);
n=read(); m=read();
for(i=1; i<=m; ++i)
{
u=read(); v=read();
cun(u, v); cun(v, u);
}
for(i=1; i<=n; ++i) f[i]=i;
for(i=1; i<=n; ++i)
if(!dep[i])
dep[i]=1, dfs(1);
for(i=1; i<=n; ++i) fa(i);
// for(i=1; i<=n; ++i) printf("%lld ", f[i]);
// printf("\n");
for(i=1; i<=m; ++i)
{
if(f[d[i*2].x]!=f[d[i*2].y])
++rd[f[d[i*2].x]], ++rd[f[d[i*2].y]];
}
for(i=1; i<=n; ++i)
if(f[i]==i&&rd[i]==1) ++lf;
printf("%lld", (lf+1)/2);
return 0;
}