*POJ 3177 Redundant Paths**

本文介绍了解决POJ3177冗余路径问题的方法,通过Tarjan算法寻找割边,并利用联通分量缩点形成树结构,最终计算出使任意两点间至少存在两条路径所需的最少边数。

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

POJ 3177 Redundant Paths
这道题是求一个变双联通分量,问你,最少加多少条边,可以使任意两个节点之间可以有两条路径
首先我们要知道,通过联通分量缩点以后我们可以形成一棵树,那么树的叶子节点数为cnt, (cnt+1)/2 便是答案,
然后就是Trajan求割边了,

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

using namespace std;
#define MAXN 55555
#define MAXE 311111

struct Edge
{
    int u, v, next;
} e[MAXE];
int head[MAXE], cnt;
int dfn[MAXN], low[MAXN], out[MAXN], vis[MAXN];
int bri[MAXN][2], fa[MAXN], belong[MAXN];
int blo, dep, nbri;

void init()
{
    cnt = blo = dep = nbri = 0;
    memset(head, -1, sizeof(head));
    memset(belong, -1, sizeof(belong));
    memset(fa, -1, sizeof(fa));
    memset(vis, 0, sizeof(vis));
    memset(out, 0, sizeof(low));
}

int findfa(int x)
{
    if(fa[x] == -1) return x;
    return fa[x] = findfa(fa[x]);
}

void unit(int x, int y)
{
    int fax = findfa(x);
    int fay = findfa(y);
    if(fax != fay)
        fa[fax] = fay;
}

void Addedge( int uu, int vv)
{
    e[cnt].u = uu, e[cnt].v = vv, e[cnt].next = head[uu];
    head[uu] = cnt++;
}

void dfs( int u, int fa)
{
    vis[u] = 1;
    dfn[u] = low[u] = ++ dep;
    int pre_num = 0;
    for( int i = head[u] ; i != -1; i = e[i].next)
    {
        int v = e[i].v;
        if( v == fa && !pre_num)
        {
            pre_num = 1;
            continue;
        }
        if(vis[v] == 0)
        {
            dfs(v, u);
            low[u] = min(low[u], low[v]);
            if(low[v] > dfn[u])
            {
                bri[nbri][0] = u;
                bri[nbri][1] = v;
                nbri++;
            }
            else
             unit(u, v);
        }
        else if(vis[v] == 1)
          low[u] = min(low[u], dfn[v]);
    }
    vis[u] = 1;
}

void solve( int n, int m)
{
    for(int i = 1; i <= n; i++)
         if(!dfn[i])
           dfs(i, -1);
    int node = 1;
    for( int i = 1; i <= n; i++)
    {
        int k = findfa(i);
        if(belong[k] == -1) belong[k] = node++;
        belong[i] = belong[k];
    }
    int count = 0;
    for( int i = 0; i < nbri; i++)
    {
        int u = bri[i][0], v = bri[i][1];
        out[belong[u]]++;
        out[belong[v]]++;
    }
    for( int i = 0; i < node; i++)
     if(out[i] == 1) count++;
    printf("%d\n",(count+1)/2);
}
int main()
{
    int n, m, u, v;
    while(scanf("%d %d",&n, &m) != EOF)
    {
        init();
        for( int i = 1; i <= m; i++)
        {
            scanf("%d %d",&u, &v);
            if( u == v) continue;
            Addedge(u, v);
            Addedge(v, u);
        }
        solve(n ,m);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值