Redundant Paths (POJ - 3177)

本文探讨了无向图的边双联通性优化问题,通过Targan算法进行缩点,形成一棵树结构,旨在解决如何通过添加最少数量的边使图中任意两点间存在至少两条路径的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【题目链接】 https://vjudge.net/contest/280753#problem/D

题意: 给你一个无向图,问你添加几条边之后使得整个图每两个点之间有不同的两条路可以到达
思路: 考察边双联通的知识点,用targan进行缩点,构成一棵树,统计每个缩点度为1(也就是叶结点),无向图没有出入度之分,故最少所需的边就为(叶结点的个数+1)/2

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=5005;
int head[N],low[N],dfn[N],belong[N],_stack[N],vis[N],du[N];
struct node
{
  int v,next;
  bool cut;
}edge[20005];
int tot,index,top,block;
void init()
{
    index=0;
    top=tot=0;
    block=0;
    memset(head,-1,sizeof head);
    memset(dfn,0, sizeof  dfn );
    memset(low,0,sizeof low );
    memset(vis,0,sizeof vis);
    memset(_stack,0,sizeof _stack);
    memset(belong,0,sizeof belong);
    memset(du,0,sizeof du);
}
void add(int u,int v)
{
    edge[top].v=v;
    edge[top].cut=0;
    edge[top].next=head[u];
    head[u]=top++;
}
void tarjan(int u,int pre)
{
    dfn[u]=low[u]=++index;
    vis[u]=1;
    _stack[tot++]=u;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
       int v=edge[i].v;
       if(v==pre)//如果引出v,而v是u的父亲,那么就不能更新low[u]
       //从而避免一条边走两次
          continue;
       if(!vis[v])
       {
           tarjan(v,u);
           low[u]=min(low[u],low[v]);
            if(low[v]>dfn[u]) //判断桥
            {
                edge[i].cut=1; //存图的时候每条边都存在相邻,如
                edge[i^1].cut=1;// 0,1  2,3 都是存相同的一条边
            }
       }
    else
           low[u]=min(low[u],dfn[v]);
    }
    int t;
    if(low[u]==dfn[u])
    {
        block++;
        do{
            t=_stack[--tot];
            vis[t]=1;
            belong[t]=block;
        }
        while(t!=u);
    }
}
int main()
{
    init();
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int u,v;
        cin>>u>>v;
        add(u,v);
        add(v,u);//无向图
    }
    tarjan(1,0);
    for(int u=1;u<=n;u++)
    {
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            if(edge[i].cut)
                du[belong[u]]++;
        }
    }
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        if(du[i]==1)
            sum++;
    }
    sum=(sum+1)/2;
    cout<<sum<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值