POJ3694 Network(tarjan求桥)

给出一个无向连通图,问加入边的过程中,桥的个数。

先用tarjan算法求出桥的总数,标记每个桥的终点。

每加入两个顶点,就查询两个顶点的lca,把lca路径上的桥都剪掉~

链式前向星:

#include<cstdio>
#include<algorithm>
#include<vector>
#include<stack>
#include<cstring>
using namespace std;
const int maxn=1e6+10;
int N,M,x,y;
int head[maxn];
int tol;
struct node {
    int u,v,next;
}edge[maxn];
void addedge (int u,int v) {
    edge[tol].u=u;
    edge[tol].v=v;
    edge[tol].next=head[u];
    head[u]=tol++;
} 
int low[maxn];
int dfn[maxn];
int q;
int pos[maxn];
int dep[maxn];
int father[maxn];
int bridge[maxn];
int depth[maxn];
int cnt;
int scc;
int ans;
stack<int> st;
void init () {
    fill(low,low+maxn,0);
    fill(dfn,dfn+maxn,0);
    fill(pos,pos+maxn,0);
    fill(depth,depth+maxn,0);
    fill(father,father+maxn,0);
    fill(bridge,bridge+maxn,0);
    memset(head,-1,sizeof(head));
    tol=0;
    cnt=0;
    scc=0;
    ans=0;
}
void tarjan (int x,int pre) {
    low[x]=dfn[x]=++cnt;
    depth[x]=depth[pre]+1;
    for (int i=head[x];i!=-1;i=edge[i].next) {
        int v=edge[i].v;
        if (v==pre) continue;
        if (!low[v]) {
            father[v]=x;
            tarjan(v,x);
            low[x]=min(low[x],low[v]);
            if (low[v]>dfn[x]) {
                ans++;
                bridge[v]=1;
            }
        }
        else if (!pos[v]) 
           low[x]=min(low[x],dfn[v]);
    }
}
void lca (int u,int v) {
    while (depth[u]<depth[v]) {
        if (bridge[v]) {
            bridge[v]=0;
            ans--;
        }
        v=father[v];
    }
    while (depth[u]>depth[v]) {
        if (bridge[u]) {
            bridge[u]=0;
            ans--;
        }
        u=father[u];
    }
    while (u!=v) {
        if (bridge[u]) {
            bridge[u]=0;
            ans--;
        } 
        if (bridge[v]) {
            bridge[v]=0;
            ans--;
        }
        u=father[u];
        v=father[v];
    }
}
int main () {
    int t=1;
    while (~scanf("%d%d",&N,&M)) {
        if (N==0&&M==0) break;
        init();
        for (int i=0;i<M;i++) {
            scanf("%d%d",&x,&y);
            addedge(x,y);
            addedge(y,x);
        }
        for (int i=1;i<=N;i++) 
            if (!low[i]) tarjan(i,i);
        scanf("%d",&q);
        printf("Case %d:\n",t++);
        while (q--) {
            scanf("%d%d",&x,&y);
            lca(x,y);
            printf("%d\n",ans);
        }
    }
    return 0;
}

邻接表:

#include<cstdio>
#include<algorithm>
#include<vector>
#include<stack>
#include<cstring>
using namespace std;
const int maxn=1e6+14;
vector<int> g[maxn];
int N,M,x,y;
int low[maxn];
int dfn[maxn];
int q;
int pos[maxn];
int depth[maxn];
int father[maxn];
int bridge[maxn];
int cnt;
int scc;
int ans;
stack<int> st;
void init () {
    fill(low,low+maxn,0);
    fill(dfn,dfn+maxn,0);
    fill(pos,pos+maxn,0);
    fill(depth,depth+maxn,0);
    fill(father,father+maxn,0);
    fill(bridge,bridge+maxn,0);
    for (int i=0;i<maxn;i++) g[i].clear();
    while (!st.empty()) st.pop();
    cnt=0;
    scc=0;
    ans=0;
}
void tarjan (int x,int pre) {
    low[x]=dfn[x]=++cnt;
    depth[x]=depth[pre]+1;
    for (int i=0;i<g[x].size();i++) {
        if (g[x][i]==pre) continue;
        if (!low[g[x][i]]) {
            father[g[x][i]]=x;
            tarjan(g[x][i],x);
            low[x]=min(low[x],low[g[x][i]]);
            if (low[g[x][i]]>dfn[x]) {
                ans++;
                bridge[g[x][i]]=1;
            }
        }
        else if (!pos[g[x][i]]) low[x]=min(low[x],dfn[g[x][i]]);
    }
}
void lca (int u,int v) {
    while (depth[u]<depth[v]) {
        if (bridge[v]) {
            bridge[v]=0;
            ans--;
        }
        v=father[v];
    }
    while (depth[u]>depth[v]) {
        if (bridge[u]) {
            bridge[u]=0;
            ans--;
        }
        u=father[u];
    }
    while (u!=v) {
        if (bridge[u]) {
            bridge[u]=0;
            ans--;
        }
        if (bridge[v]) {
            bridge[v]=0;
            ans--;
        }
        u=father[u];
        v=father[v];
    }
}
int main () {
    int t=1;
    while (~scanf("%d %d",&N,&M)) {
        if (N==0&&M==0) break;
        init ();
        for (int i=0;i<M;i++) {
            scanf ("%d %d",&x,&y);
            g[x].push_back(y);
            g[y].push_back(x);
        }
        for (int i=1;i<=N;i++) 
        if (!low[i]) tarjan(i,i);
        scanf("%d",&q);
        printf ("Case %d:\n",t++);
        while (q--) {
            scanf ("%d %d",&x,&y);
            lca (x,y);
            printf ("%d\n",ans);
        }
    }
    return 0;
}

 

posted @ 2020-02-15 19:59  zlc0405  阅读(105)  评论(0编辑  收藏  举报