poj 3694 Network 邊雙連通


給一幅圖,若干個操作,每個操作時連接兩個點,對於每個操作之后的圖判斷圖中還有幾條割邊

解法

先求出最初的圖中有幾條割邊bridge

在求的過程中順便建立一個方向,相當於變成有向圖,如果發現某條邊不是割邊,就利用並查集將兩個點合並,也可以不合並,但是速度上就相差很多了

最后,一個聯通塊中的點就只以一個點為根了

還有,如果s-t是割邊,就標記一下t

現在要連接兩個點a,b

在找他們的LCA的時候如果發現某條邊是割邊就bridge--

因為需要一層層上去,遍歷到從a,b到LCA的每條邊,所以這個過程就直接暴力網上找了,不知還有沒有什么更好的方法

View Code
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=100010;
struct Edge
{
    int s,t;
    int next;
    int vis;
}edge[1000005];
int head[maxn];
int E=0;
void add_edge(int s,int t)
{
    edge[E].s=s;
    edge[E].t=t;
    edge[E].vis=0;
    edge[E].next=head[s];
    head[s]=E++;
}
int Time,N,M;
int dfn[maxn],low[maxn];
int  Top;
int bridge;
inline int min(int a,int b){return a<b?a:b;}
int f[maxn];
bool mark[maxn];
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
void dfs(int s)
{
    int i,t;
    dfn[s]=low[s]=++Time;
    for (i=head[s];i!=-1;i=edge[i].next)
    {    
        if(edge[i].vis)continue;    
        edge[i].vis=edge[i^1].vis=1;
        t=edge[i].t;
        if (!dfn[t])
        {
            f[t]=s;
            dfs(t);
            low[s]=min(low[s],low[t]);
        }
        else low[s]=min(low[s],dfn[t]);
        if(low[t]<=dfn[s])
        {
            int x=find(t);
            int y=find(s);
            if(x!=y)    f[x]=y;
        }
        if(low[t]>dfn[s])
        {
            mark[t]=true;
            bridge++;
        }
    }
}
void SCC(int n)
{
    int i;bridge=0;f[1]=1;
    memset(mark,false,sizeof(mark));
    memset(dfn,0,sizeof(int)*(n+1));
    for(i=1;i<=n;i++)
    {
        if(!dfn[i])
        dfs(i);
    }
}
void LCA(int a,int b)
{
    if(dfn[a]<dfn[b]) 
    {
        a^=b;
        b^=a;
        a^=b;
    }
    while(dfn[a]>dfn[b])
    {
        if(mark[a]) {bridge--;mark[a]=false;}
        a=f[a];
    }
    while(a!=b)
    {
        if(mark[a]){bridge--;mark[a]=false;}
        a=f[a];
        if(mark[b]){bridge--;mark[b]=false;}
        b=f[b];
    }
}
int main()
{
    int n,m,i,q,a,b,ca=1;
    while(scanf("%d%d",&n,&m),(n||m))
    {
        E=0;
        memset(head,-1,sizeof(head));
        for(i=0;i<m;i++)
        {
            scanf("%d%d",&a,&b);
            add_edge(a,b);
            add_edge(b,a);
        }
        SCC(n);
        printf("Case %d:\n",ca++);
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d%d",&a,&b);
            LCA(a,b);
            printf("%d\n",bridge);
        }
        puts("");
    }
    return 0;
}




注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
  © 2014-2022 ITdaan.com 联系我们: