BZOJ 1718 浅谈边双连通分量tarjan求法

本文介绍了如何使用Tarjan算法求解边双连通分量的问题。作者通过自身的学习经历,讲述了在数论学习中的挑战,并选择通过图论题目来调整状态。题目要求确定使图变为边双连通图所需的最少新增边数,解决方案是先对原图进行Tarjan算法处理,缩点后将树中所有度为1的节点两两连接。代码实现中需注意处理无向图和可能存在的重边情况。
摘要由CSDN通过智能技术生成

这里写图片描述
世界真的很大
这几天学数论,算几,人都学傻了,什么FFT,高消的,会了有什么用呢?还不是死在没开long long上
这几天的亲身经历。。。
赶快做几道图论压压惊
看题先:
description:

In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1..F) to another field, Bessie and the rest of the herd are forced to cross near the Tree of Rotten Apples. The cows are now tired of often being forced to take a particular path and want to build some new paths so that they will always have a choice of at least two separate routes between any pair of fields. They currently have at least one route between each pair of fields and want to have at least two. Of course, they can only travel on Official Paths when they move from one field to another. Given a description of the current set of R (F-1 <= R <= 10,000) paths that each connect exactly two different fields, determine the minimum number of new paths (each of which connects exactly two fields) that must be built so that there are at least two separate routes between any pair of fields. Routes are considered separate if they use none of the same paths, even if they visit the same intermediate field along the way. There might already be more than one paths between the same pair of fields, and you may also build a new path that connects the same fields as some other path.

N个点,M条边,问最少添加几条边使得图中任意两点互相到达且至少有两条完全不一样的路径。

input

* Line 1: Two space-separated integers: F and R * Lines 2..R+1: Each line contains two space-separated integers which are the fields at the endpoints of some path.

output

* Line 1: A single integer that is the number of new paths that must be built.

这题废话超级多,其实题目也就一句话
题目已经说出来了,任意两点之间至少两条完全不一样的路径,这里的完全不一样是指两条路径之间没有重合的部分,很明显就是在说边双连通分量
就是说给原图加多少条边可以使得其整个的变为一个边双连通图
所以首先想到把原图tarjan跑一遍边双连通分量缩一下点,就会得到一颗无向图的树,对于树的每一个度为1的点,两两连起来就好
而求边双连通分量和点双连通分量不同,和强连通分量的求法几乎一毛一样,唯一不同的是无向图和有向图的区别罢了
所以只需要在tarjan里面判断不走回头路就好
这道题有些特别,可能有重边,所以不能单单记录一下从那个点走来,还要记录是从那条边走来的
完整代码:

#include<stdio.h>
#include<algorithm>
#include<stack>
#include<cstring>
using namespace std;

struct edge
{
    int v,u,last;
}ed[100010];

stack <int> stk;

int n,m,num=0,mum=0,idx=0,cnt=0,ans=0;
int head[100010],ins[100010],dfn[100010],low[100010],vis[100010];
int place[100010],du[100010],fa[100010],tot[10010];

void add(int u,int v)
{
    num++;
    ed[num].u=u;
    ed[num].v=v;
    ed[num].last=head[u];
    head[u]=num;
}

void tarjan(int u)
{
    dfn[u]=low[u]=++idx;
    ins[u]=vis[u]=1;
    stk.push(u);
    for(int i=head[u];i;i=ed[i].last)
    {
        int v=ed[i].v;
        if(tot[i]==fa[u]) continue ;
        if(!vis[v])
        {
            fa[v]=tot[i];
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else
            low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        int t=-1;cnt++;
        while(t!=u)
        {
            t=stk.top();
            place[t]=cnt;
            stk.pop();
            ins[t]=0;
        }
    }
}

void ReBuild()
{
    for(int i=1;i<=num;i++)
    {
        int u=ed[i].u,v=ed[i].v;
        if(place[u]!=place[v])
            du[place[u]]++,du[place[v]]++;
    }
    for(int i=1;i<=cnt;i++)
        if(du[i]==2) ans++;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v);tot[num]=++mum;
        add(v,u);tot[num]=mum;
    }
    for(int i=1;i<=n;i++)
        if(!vis[i]) tarjan(i);
    ReBuild();
    printf("%d\n",(ans+1)/2);
    return 0;
}
/*
EL PSY CONGROO
*/

嗯,就是这样

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值