UVA 10972(边双连通分量)

21 篇文章 0 订阅
9 篇文章 0 订阅

题目链接:UVA 10972

解题思路:
这题的题意很简单,就是给一个无向图,然后要求我们把所有的边都变成有向边,然后再另外添加一些有向边,最终用最少的边把有向图变成强连通的。一眼看过去是懵比的,然而仔细一想,转化后的有向图强连通即原图边双连通啊,于是题目转化成添加最少的边把原图变成边双连通图。先跑一遍Tarjan算法后缩点统计度为0和1的结点即可。

代码:

#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define maxn 1005
#define maxm 1000005

using namespace std;

struct Edge{
    int u,v;
    Edge(int u=0,int v=0):u(u),v(v){}
}e[maxm];
int n,m,stamp,dfn[maxn],low[maxn],bccno[maxn],bcc_cnt;
vector<int> vec[maxn];
bool isbridge[maxm];

void tarjan(int index,int fa)
{
    int tmp;
    dfn[index]=low[index]=++stamp;
    for(int i=0;i<vec[index].size();i++)
    {
        tmp=e[vec[index][i]].v;
        if(!dfn[tmp])
        {
            tarjan(tmp,index);
            low[index]=min(low[index],low[tmp]);
            if(low[tmp]>dfn[index])
                isbridge[vec[index][i]]=isbridge[vec[index][i]^1]=1;
        }
        else if(dfn[tmp]<dfn[index] && tmp!=fa)
        {
            low[index]=min(low[index], dfn[tmp]);
        }
    }
}

void dfs(int index)
{
    dfn[index]=1;
    bccno[index]=bcc_cnt;
    for(int i=0;i<vec[index].size();i++)
    {
        int tmp=vec[index][i];
        if(isbridge[tmp])
            continue;
        if(!dfn[e[tmp].v])
        {
            dfs(e[tmp].v);
        }
    }
}

void find_ebcc(){
    bcc_cnt=stamp=0;
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(bccno,0,sizeof(bccno));
    memset(isbridge,0,sizeof(isbridge));
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i, -1);
    memset(dfn,0,sizeof(dfn));
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i])
        {
            bcc_cnt++;
            dfs(i);
        }
    }               
}

int main()
{
    while(~scanf("%d %d",&n,&m))
    {
        memset(vec,0,sizeof(vec));
        int x,y;
        for(int i=0;i<m;i++)
        {
            scanf("%d %d",&x,&y);
            e[i*2]=Edge(x,y);
            vec[x].push_back(2*i);
            e[i*2+1]=Edge(y,x);
            vec[y].push_back(2*i+1);
        }
        find_ebcc();

        if(bcc_cnt==1)
            printf("0\n");
        else
        {
            memset(dfn,0,sizeof(dfn));
            for(int i=0;i<m*2;i+=2)
            {
                x=e[i].u, y=e[i].v;
                if(bccno[x]!=bccno[y])
                {
                    dfn[bccno[x]]++;
                    dfn[bccno[y]]++;
                }
            }

            int a=0,b=0;
            for(int i=1;i<=bcc_cnt;i++)
            {
                if(dfn[i]==0)
                    a++;
                if(dfn[i]==1)
                    b++;
            }

            printf("%d\n",a+(b+1)/2);           
        }
    }

    return 0;
}

总结:
1、再次说明,图论题很多时候想一想,找找规律就懂了。
2、通过这题找到了我模板的一个bug,还好现在找到了QAQ

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值