HDU3394Railway Tarjan连通算法
Now we know the plan, and can you tell us how many railways are no need to build and how many railways where *** might happen.
InputThe Input consists of multiple test cases. The first line of each test case contains two integers, n (0 < n <= 10000), m (0 <= m <= 100000), which are the number of locations and the number of the railways. The next m lines, each line contains two integers, u, v (0 <= u, v < n), which means the manger plans to build a railway on the road between u and v.
You can assume that there is no loop and no multiple edges.
The last test case is followed by two zeros on a single line, which means the end of the input.OutputOutput the number of railways that are no need to build, and the number of railways where *** might happen. Please follow the format as the sample.Sample Input
8 10
0 1
1 2
2 3
3 0
3 4
4 5
5 6
6 7
7 4
5 7
0 0
Sample Output
1 5
过了一周再来总结这几道题,为什么这道题是每条边访问后就退栈stk[top--],而“warm up”是访问完所以边再退栈。是因为此题不缩点,只是取值,所以不必等访问完所有边再退栈。相反,1-2-4组成一个环,1-3-5组成一个环,点相联通的情况下1-2-4-3-5都应该再这个缩点里,访问完一条边就退栈会导致1-2-4和3-5不在一个缩点里。
比如HDU2242不需要缩点,可以遇到一割边就处理。而HDU4612就必须访问完相连的割边再缩点。
又过了一周,再总结:
点的双连通存桥(边),每访问一条边操作一次。
边的双连通存割点(点),访问完所有边后操作。
尚有疑惑
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=10010;
const int maxm=200010;
int Laxt[maxn],Next[maxm],To[maxm],cnt,vis[maxn];
int dfn[maxn],low[maxn];
int times,ans,cute_cnt,n,m;
int q[maxn],q_cnt,scc[maxn],scc_cnt;
int stk[maxn],top;
void _init()
{
memset(Laxt,0,sizeof(Laxt));
memset(dfn,0,sizeof(dfn));
memset(scc,0,sizeof(scc));
memset(vis,0,sizeof(vis));
ans=cute_cnt=top=scc_cnt=cnt=times=0;
}
void _add(int u,int v)
{
Next[++cnt]=Laxt[u];
Laxt[u]=cnt;
To[cnt]=v;
}
void _count()//找环
{
int e=0;
for(int i=1;i<=q_cnt;i++)
for(int j=Laxt[q[i]];j;j=Next[j])
if(scc[To[j]]==scc[q[i]]) e++;
e/=2;
if(e>q_cnt) ans+=e;
}
void _tarjan(int u,int v){
dfn[u]=low[u]=++times;
int num_v=0;
stk[++top]=u;
for(int i=Laxt[u];i;i=Next[i]){
if(To[i]==v) continue;//此题无重边
if(!dfn[To[i]]){
_tarjan(To[i],u);
if(low[u]>low[To[i]]) low[u]=low[To[i]];
if(low[To[i]]>dfn[u]) cute_cnt++;//割边
if(dfn[u]<=low[To[i]]){//小于是个环,等于是个点,都要处理
q_cnt=0;//环内的点
scc_cnt++;
for(;;){
int tmp=stk[top--];
scc[tmp]=scc_cnt;
q[++q_cnt]=tmp;
if(tmp==To[i]) break;
}
scc[u]=scc_cnt;
q[++q_cnt]=u;
_count();
}
}
else if(dfn[To[i]]<low[u]) low[u]=dfn[To[i]];
}
}
int main()
{
int i,j,k,u,v;
while(~scanf("%d%d",&n,&m)){
if(n==0&&m==0) return 0;
_init();
while(m--){
scanf("%d%d",&u,&v);
u++;v++;
_add(u,v);
_add(v,u);
}
for(i=1;i<=n;i++)
if(!dfn[i]) _tarjan(i,-1);
printf("%d %d\n",cute_cnt,ans);
}
return 0;
}

浙公网安备 33010602011771号