poj 3694 Network

http://poj.org/problem?id=3694

用了Tarjan bfs 缩点

所以时间复杂度比较高

思路 先建双向图 重边要处理(用一个变量表示边数)

用Tarjan算法缩点

重新建了一个缩点后的双向图

增加边时用bfs 搜索路径上的桥如果还有就对数量进行操作并将此桥标记为没有

每次重复

#include<iostream>

#include<cstring>

#include<stack>

#include<cstdio>

#include<queue>



using namespace std;



const int N=100005;

struct node

{

    struct tt *next;

}mem[N];//原图

struct nodeq

{

    struct ttq *next;

}memq[N];

struct tt

{

    struct tt *next;

    int j;

    int k;

};

struct ttq

{

    struct ttq *next;

    int j;

    bool bridge;//此桥是否存在

};//缩点后的图

void build(int i,int j)

{

    struct tt *t;

    t=mem[i].next;

    while(t!=NULL)

    {

        if(t->j==j)

        {

            ++t->k;//记录此路的数量

            return ;

        }

        t=t->next;

    }

    t=new tt;

    t->j=j;

    t->k=1;

    t->next=mem[i].next;

    mem[i].next=t;

}

bool in[N];

int low[N];

int dfn[N];

stack<int>str;

int time;

bool visited[N];

int uppoint[N];//缩点数组

int f[N];

int l,r;

int ans;

void Clear(int n)

{

    for(int i=1;i<=n;++i)

    {mem[i].next=NULL;memq[i].next=NULL;}

}

void Tarjan(int pre,int k,int x)

{

    ++time;

    visited[x]=true;

    in[x]=true;

    dfn[x]=low[x]=time;

    str.push(x);

    struct tt *t=mem[x].next;

    while(t!=NULL)

    {

        if(visited[t->j]==false)

        {

            Tarjan(x,t->k,t->j);

            low[x]=min(low[x],low[t->j]);

        }

        else if(in[t->j]==true&&(pre!=t->j||(pre==t->j&&k>1)))//如果搜到上一个点则必须是不只一条路

        {

            low[x]=min(low[x],dfn[t->j]);

        }

        t=t->next;

    }

    if(low[x]==dfn[x])

    {

        while(str.top()!=x)

        {

            uppoint[str.top()]=x;//缩点 全缩成x

            in[str.top()]=false;

            str.pop();

        }

       uppoint[x]=x;

       in[str.top()]=false;

       str.pop();

    }

}

void buildtree(int i,int j)//建新图

{

    struct ttq *t=new ttq;

    t->j=j;

    t->bridge=true;//初始化存在

    t->next=memq[i].next;

    memq[i].next=t;

}

void dfs(int x)

{

    visited[x]=true;

    struct tt *t=mem[x].next;

    while(t!=NULL)

    {

        if(!visited[t->j])

        {

            if(uppoint[x]!=uppoint[t->j])

            {

                ++ans;

                buildtree(uppoint[x],uppoint[t->j]);//双向

                buildtree(uppoint[t->j],uppoint[x]);//双向

            }

            dfs(t->j);

        }

        t=t->next;

    }

}

void rebuild()

{

    memset(visited,false,sizeof(visited));

    dfs(1);

}

int dec(int st,int nd)

{

    queue<int>str;

    memset(visited,false,sizeof(visited));

    str.push(st);

    f[st]=st;

    visited[st]=true;

    struct ttq *t;

    while(1)//bfs 找两点路径

    {

        int x=str.front();

        if(x==nd){break;}

        str.pop();

        t=memq[x].next;

        while(t!=NULL)

        {

            if(!visited[t->j])

            {

                visited[t->j]=true;

                f[t->j]=x;

                str.push(t->j);

            }

            t=t->next;

        }

    }

    int k=nd;

    int num=0;

    while(k!=st)

    {

        int pre=f[k];

        t=memq[pre].next;

        while(t!=NULL)

        {

            if(t->j==k)

            {

               if(t->bridge==true)

               {

                   ++num;t->bridge=false;//如果此桥存在 则计数并标记

               }

               break;

            }

            t=t->next;

        }

        t=memq[k].next;

        while(t!=NULL)//反向的也要

        {

            if(t->j==pre)

            {

               if(t->bridge==true)

               {

                   ++num;t->bridge=false;

               }

               break;

            }

            t=t->next;

        }

        k=pre;

    }

    return num/2;//正向加反向的 所以要除2

}

int main()

{

    int n,m;

    for(int w=1;;++w)

    {

        scanf("%d %d",&n,&m);

        if(n==0&&m==0)

        break;

        while(m--)

        {

            int i,j;

            scanf("%d %d",&i,&j);

            build(i,j);

            build(j,i);

        }

        memset(in,false,sizeof(in));

        memset(visited,false,sizeof(visited));

        while(!str.empty())

        str.pop();

        time=0;

        Tarjan(1,1,1);

        ans=0;

        rebuild();

        int q;

        scanf("%d",&q);

        printf("Case %d:\n",w);

        while(q--)

        {

            scanf("%d %d",&l,&r);

            l=uppoint[l];r=uppoint[r];

            if(ans!=0&&l!=r)

            {

                ans-=dec(l,r);

            }

            printf("%d\n",ans);

        }

        printf("\n");

        Clear(n);

    }

    return 0;

}





 

 

你可能感兴趣的:(NetWork)