poj 3177&&3352 求边双联通分量,先求桥,然后求分量( 临界表代码)

/*这道题是没有重边的,求加几条边构成双联通,求边联通分量,先求出桥然后缩点,成一个棵树
找叶子节点的个数*/
#include<stdio.h>//用容器写在3177这个题上会超内存,但是用临界表过了
#include<string.h>/*此代码为临界表代码*/
#define N  5100
struct node {
int u,v,next;
}bian[N*4];
int dfn[N],low[N],index,f[N*4],n,head[N],yong;
int Min(int a,int b) {
return a>b?b:a;
}
void addedge(int u,int v) {//建边
bian[yong].u=u;
bian[yong].v=v;
bian[yong].next=head[u];
head[u]=yong++;
}
void tarjan(int u,int pre) {//
 dfn[u]=low[u]=++index;
 int i;
 for(i=head[u];i!=-1;i=bian[i].next) {
    int v=bian[i].v;
    if(i==(pre^1))continue;
    if(!dfn[v]) {
        tarjan(v,i);
        low[u]=Min(low[u],low[v]);//
        if(low[v]>dfn[u])//标记桥
            f[i]=f[i^1]=1;//标记双向的边
    }
    else
        low[u]=Min(low[u],dfn[v]);
 }
}
int cnt,c[N];
void dfs(int u,int fa) {//缩点
int i;
 c[u]=cnt;//不能放到循环里面,
for(i=head[u];i!=-1;i=bian[i].next) {
        int v=bian[i].v;
    if(!f[i]&&!c[v]&&i!=(fa^1))//桥不能走,不能回头路,没有被缩过
        dfs(v,i);
}
return ;
}
int degree[N];
int slove() {
    int i;
    cnt=1;
    memset(c,0,sizeof(c));
    for(i=1;i<=n;i++)//缩点
            if(!c[i]) {
        dfs(i,-1);
        cnt++;
            }
    memset(degree,0,sizeof(degree));
    for(i=0;i<yong;i++) {
            int u,v;
    u=bian[i].u;
    v=bian[i].v;
            if(c[u]!=c[v]) {//所有边中
                degree[c[u]]++;
                degree[c[v]]++;//记录度数
            }
    }
    int leave=0;
    for(i=1;i<cnt;i++) {//度数为一的叶子节点,因为为双向边
        if(degree[i]==2)
            leave++;
    }
    return  (leave+1)/2;
}
int main() {
   int m,i,a,b,ans;
   while(scanf("%d%d",&n,&m)!=EOF) {
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(f,0,sizeof(f));
    yong=0;
    memset(head,-1,sizeof(head));
    index=0;
    while(m--){
        scanf("%d%d",&a,&b);
    addedge(a,b);
    addedge(b,a);
    }
    for(i=1;i<=n;i++)
        if(!dfn[i])
        tarjan(i,-1);
        ans=slove();
        printf("%d
",ans);
   }
return 0;
}

原文地址:https://www.cnblogs.com/thefirstfeeling/p/4410689.html