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;
}


 

 

posted on 2012-05-30 22:10  夜->  阅读(212)  评论(0编辑  收藏  举报