HDU -- 3394 Railway ( 双连通 求块判断环)

题目大意:公园有n个景点,公园的管理员要计划修建m条能形成环形的观光路径。此时,如果一条路径没有被任何一个环路所使用,它就是不需要的边,多余边;如果一个路径被多余一个环路所使用,那它就是冲突边;求多余边和冲突边的个数。

思路分析:

①:多余边:即是双连通的割边;

②:冲突边:把图分成多个块,求块里的边数,如果块里的边数大于点数,就说明这个块里的边都是冲突边;如何理解呢,如果一个块中的边多余点数,就说明有边把最外边的大环分割成了几个小环,那么小环和小环之间,小环和大环之间就会形成公用边,进而块里的环也就都是冲突边了。

代码实现:

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
#include<algorithm>
#include<iostream>
//#pragma comment(linker, "/STACK:102400000,102400000")
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define MEM(a) (memset((a),0,sizeof(a)))
#define MEME(a) (memset((a),-1,sizeof(a)))
#define MEMX(a) (memset((a),0x3f,sizeof(a)))
using namespace std;
const int N=10005;
const int M=100005;
int dfn[N],low[N],vis[N],block[N],st[N],bccn,top,s_top,tim,ans1,ans2,cnt,n,m;
bool in[N];
struct Edge{
    int v;
    Edge *next;
}*head[N],e[M*2];
void Addedge(int from,int to){
    Edge *p=&e[top++];
    p->v=to;
    p->next=head[from];
    head[from]=p;
}
void Find_edge(){
    int sum=0,u,v;
    for(int i=1;i<=cnt;++i){
        u=block[i];
        for(Edge *p=head[u];p;p=p->next){
            if(in[p->v]) sum++;
        }
    }
    sum/=2;
    if(sum>cnt) ans2+=sum;
}
void Tarjan_bcc(int u,int fa){
    dfn[u]=low[u]=++tim;
    st[++s_top]=u;
    int v,tmp;
    for(Edge *p=head[u];p;p=p->next){
        v=p->v;
        if(v==fa) continue;
        if(!dfn[v]){
            Tarjan_bcc(v,u);
            low[u]=Min(low[u],low[v]);
            if(low[v]>dfn[u]) ans1++;
            if(low[v]>=dfn[u]){
                cnt=0;
                memset(in,0,sizeof(in));
                do{
                    tmp=st[s_top--];
                    block[++cnt]=tmp;
                    in[tmp]=1;
                }while(tmp!=v);
                block[++cnt]=u;
                in[u]=1;
                Find_edge();
            }
        }else low[u]=Min(low[u],dfn[v]);
    }
}
int main(){
    int a,b;
    while(~scanf("%d%d",&n,&m),(n||m)){
        MEM(head),MEM(dfn),MEM(low),MEM(block),MEM(in);
        bccn=top=s_top=ans1=ans2=tim=0;
        for(int i=1;i<=m;++i){
            scanf("%d%d",&a,&b);
            Addedge(a,b);
            Addedge(b,a);
        }
        for(int i=0;i<n;++i) if(!dfn[i]) Tarjan_bcc(i,-1);
        printf("%d %d\n",ans1,ans2);
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值