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

7 篇文章 0 订阅
6 篇文章 0 订阅

这题想到一半了,最后缩点以后的统计答案挂了= =。。。
题意就不说了,问你加入多少条边能使得所有边都是一个边双。
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[N], low[N],dep[N];
bool vis[N],isc[N],isb[N];
int head[N], go[N], nxt[N];
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[N];
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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值