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;
}
浙公网安备 33010602011771号