觉得这道题目蛮有意义的
首先求割边 缩图成树 计算叶子结点与根结点连通所需要添加的最少边既可
#include
<
iostream
>
using
namespace
std;
//
点编号从1开始
typedef
struct
{
long
v,next;
}Edge;
const
long
MAXN
=
2000
;
long
du[MAXN];
long
p[MAXN];
Edge e[MAXN];
long
eid;
long
dfn[MAXN], low[MAXN], deep, color[MAXN], com;
long
n,r;
inline
void
insert(
long
from,
long
to)
{
e[eid].next
=
p[from];
e[eid].v
=
to;
p[from]
=
eid
++
;
//
以下为无向图使用
swap(from, to);
e[eid].next
=
p[from];
e[eid].v
=
to;
p[from]
=
eid
++
;
}
long
min(
long
a,
long
b)
{
return
a
<
b
?
a:b;
}
inline
void
dfs(
int
i,
int
f)
{
dfn[i]
=
low[i]
=
++
deep;
long
j;
for
(j
=
p[i]; j
!=-
1
; j
=
e[j].next)
{
int
k
=
e[j].v;
if
(
!
dfn[k])
{
dfs(k, i);
low[i]
=
min(low[i], low[k]);
}
else
if
(k
!=
f)
{
low[i]
=
min(low[i], dfn[k]);
}
}
}
inline
void
set_color(
int
i)
{
long
j;
for
(j
=
p[i]; j
!=-
1
; j
=
e[j].next)
{
int
k
=
e[j].v;
if
(
!
color[k])
{
if
(low[k]
>
dfn[i]) color[k]
=
++
com;
else
color[k]
=
color[i];
set_color(k);
}
}
}
inline
void
biconnect()
{
deep
=
0
;
dfs(
1
,
-
1
);
com
=
1
;
color[
1
]
=
1
;
set_color(
1
);
}
int
main()
{
while
(scanf(
"
%ld %ld
"
,
&
n,
&
r)
!=
EOF)
{
long
i,j;
memset(p,
-
1
,
sizeof
(p));
memset(du,
0
,
sizeof
(du));
memset(low,
0
,
sizeof
(low));
memset(color,
0
,
sizeof
(color));
memset(dfn,
0
,
sizeof
(dfn));
eid
=
0
;
for
(i
=
0
;i
<
r;
++
i)
{
long
from,to;
scanf(
"
%ld %ld
"
,
&
from,
&
to);
insert(from,to);
}
//
关键边求解
biconnect();
for
(i
=
1
; i
<=
n; i
++
)
{
long
a
=
color[i];
for
(j
=
p[i]; j
!=-
1
; j
=
e[j].next)
{
long
b
=
color[e[j].v];
if
(a
!=
b)
{
++
du[a];
}
}
}
long
leap
=
0
;
for
(i
=
1
; i
<=
com; i
++
)
{
if
(du[i]
==
1
)
{
++
leap;
}
}
printf(
"
%ld\n
"
, (leap
+
1
)
/
2
);
}
return
0
;
}