HDU 4612

给一个连通的无向图,随意添加一条边要使添加后的桥最少。缩点后求出树形图的直径,总的强连通分量-直径就行了。

要手动扩栈,之后用C++交。

第一次用Tarjan算法,之前一直在逃避图论,真去学了,也没什么难的,代码敲了两遍,第二次果断1A了,一如做过的题,还有必要再做一遍。

#pragma comment(linker,"/STACK:102400000,102400000")
#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<algorithm>
#include<map>
using namespace std;

#define N 200010
#define M 1000010

struct NODE{
    int v,next;
}node[M*2];
bool vis[M];
int head[N];
int dp[N][2];
int dfn[N];
int low[N];
int cnt,ret,n,m;

void addEdge(int from,int to){
    node[cnt].next=head[from];
    node[cnt].v=to;
    head[from]=cnt++;
}

void Tarjan(int u){
    dp[u][0]=dp[u][1]=0;
    dfn[u]=low[u]=cnt++;
    for(int i=head[u];i!=-1;i=node[i].next){
        int j=node[i].v;
        if(vis[i>>1]) continue;
        vis[i>>1]=1;
        if(dfn[j]==0){
            Tarjan(j);
            ret+=low[j]>dfn[u];
            int temp = dp[j][0]+(low[j]>dfn[u]);
            if(temp>dp[u][0]){
                dp[u][1]=dp[u][0];
                dp[u][0]=temp;
            }else if(temp>dp[u][1]){
                dp[u][1]=temp;
            }
            low[u]=min(low[u],low[j]);
        }else{
            low[u]=min(low[u],dfn[j]);
        }
    }
}
int main(){
    while(scanf("%d %d",&n,&m)!=EOF&&n+m){
        memset(head,-1,sizeof(head));
        memset(vis,0,sizeof(vis));
        memset(dp,0,sizeof(dp));
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        ret=cnt=0;
        for(int i=0;i<m;i++){
            int v,u;
            scanf("%d %d",&v,&u);
            addEdge(u,v);
            addEdge(v,u);
        }
        cnt=1;
        Tarjan(1);
        int temp=0;
        for(int i=1;i<=n;i++){
            temp=max(temp,dp[i][0]+dp[i][1]);
        }
        printf("%d\n",ret-temp);
    }
    return 0;
}
/**
test data
imput
6 7
4 6
1 2
1 2
2 3
4 3
4 3
3 5
output
1
**/


你可能感兴趣的:(Tarjan)