POJ3177 Redundant Paths

gate

用时:断断续续地debug,大概用了120min?

板子题.
求将一个无向图变成边双联通图最少的加边数.
结论:设原图叶子节点(入度为1的)的数量为(x),答案即为((x+1)/2)
证明:将叶子节点两两相连.

首先(tarjan)求出所有强连通分量,只保留割边.
缩点后判断有多少入度为1的节点即可.

bug:
因为要用^1来取一条边的反向边,所以下标必须从偶数开始.
但是写链前时,i==0是退出条件,所以要从2开始!我是傻逼(1/1)

code

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#define MogeKo qwq
using namespace std;

const int maxn = 1e5+10;
int n,m,x,y,sum,cnt,now,num,top,inn[maxn];
int to[maxn],head[maxn],nxt[maxn];
int dfn[maxn],low[maxn],sta[maxn],col[maxn];
bool insta[maxn],cut[maxn];

void add(int x,int y){
    to[++cnt] = y;
    nxt[cnt] = head[x];
    head[x] = cnt;
}

void tarjan(int u,int fa){
    dfn[u] = low[u] = ++now;
    sta[++top] = u;
    insta[u] = true;
    for(int i = head[u];i;i = nxt[i]){
        int v = to[i];
        if(v == fa) continue;
        if(!dfn[v]){
            tarjan(v,u);
            low[u] = min(low[u],low[v]);
            if(low[v] > dfn[u])
                cut[i] = cut[i^1] = true;
        }
        else if(insta[v])
            low[u] = min(low[u],dfn[v]);
    }
    if(low[u] == dfn[u]){
        int v;
        num++;
        do{
            v = sta[top--];
            insta[v] = false;
            col[v] = num;
        } while(v != u);
    }
}

int main(){
    scanf("%d%d",&n,&m);
    cnt = 1;
    for(int i = 1;i <= m;i++){
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
   for(int i = 1;i <= n;i++)
       if(!dfn[i]) tarjan(i,i);
   for(int i = 2;i <= m*2+1;i++)
       if(cut[i])
           inn[col[to[i]]]++;
   for(int i = 1;i <= num;i++)
       if(inn[i] == 1)
           sum++;
   printf("%d
",(sum+1)/2);
   return 0;
}

原文地址:https://www.cnblogs.com/mogeko/p/13213907.html