您的位置:首页 > 其它

bzoj1718[Usaco2006 Jan] Redundant Paths 分离的路径 边双连通分量

2017-06-17 09:50 429 查看
这题想到一半了,最后缩点以后的统计答案挂了= =。。。

题意就不说了,问你加入多少条边能使得所有边都是一个边双。

n有点小了,怀疑有n^2水法。

求出边双以后缩点比较显然,然后我就有点蒙逼了,不知道怎么统计答案。。

想了dp和二分等奇怪姿势,然而好像都没用。

后来看了一波题解才发现是结论= =一棵树,要让他任意两点之间有超过1条路径相连,答案是(叶子节点个数+1)/2。

为啥呢?因为,一棵树,我们一开始不加边,他们之间的路径肯定是向上走然后相交,那么第二条路径,我们要加的边尽量少,则重复的边尽量少,所以我们在不同子树之间的叶子节点之间两两配对就好了,当然如果只有一个叶子节点就两个都连过去。。

注意最后统计叶子节点的时候,只有是桥的边才是树上的边。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
int n, m;
const int N = 1e5 + 5;
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 * 10 + ch - '0'; ch = getchar(); }
return x*f;
}
int dfn
, low
,dep
;
bool vis
,isc
,isb
;
int head
, go
, nxt
;
int tot=1, cnt, tim;
inline void add(int x, int y)
{
go[++tot] = y;
nxt[tot] = head[x];
head[x] = tot;
}
inline void dfs(int x, int pre)
{
dfn[x]=low[x]=++tim;
for (int i = head[x]; i; i = nxt[i])
{
int v = go[i];
if ((i^1)!=pre)
if (!dfn[v])
dfs(v, i),
low[x] = min(low[x], low[v]);
else low[x] = min(low[x], dfn[v]);
}
if (pre&&low[x] == dfn[x])
isb[pre] = isb[pre ^ 1] = 1;
}
int bel
;
inline void rebuild(int x, int num)
{
bel[x] = num;
for (int i = head[x]; i; i = nxt[i])
{
int v = go[i];
if (!bel[v] && !isb[i])rebuild(v, num);
}
}
int main()
{
n = read(), m = read();
fo(i, 1, m)
{
int x=read(), y=read();
add(x, y);
add(y, x);
}
int blocksum = 0;
fo(i, 1, n)if (!dfn[i])dfs(1,0);
fo(i, 1, n)if (!bel[i])rebuild(i, ++blocksum);
for (int i = 2; i <= tot; i += 2)if (isb[i])dep[bel[go[i]]]++, dep[bel[go[i ^ 1]]]++;
int ans = 0;
fo(i, 1, blocksum)if (dep[i] == 1)ans++;
printf("%d\n", (ans + 1) >> 1);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: