| ||||||||||
| Online Judge | Problem Set | Authors | Online Contests | User | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest | |||||||||
提供思想/代码和两组数据1:对图进行强联通缩点变成一棵树,并求出树上每个点的深度和该点的直接父亲以及指向的祖先(fa,pre表示)
2:对于q个询问,每个询问(u,v),进行lca最近公共祖先查找,查找过程中利用并查集思想将u,v查找到祖先过程中的经过的点的祖先全部变成u,v查找到的祖先(具体请看代码)
整个算法复杂度O(Q+N)
数据:
6 5
1 2
1 3
2 4
2 5
4 6
3
4 5
2 3
1 6
6 5
1 2
1 3
2 4
2 5
4 6
3
4 5
2 3
5 6
答案:3 1 0
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#include <map>
#include <cmath>
#include <iomanip>
#define INF 99999999
typedef long long LL;
using namespace std;
#pragma comment(linker,"/STACK:102400000,102400000")
const int MAX=100000+10;
int uu[MAX*2],vv[MAX*2];
int n,m,size,top,index,sum;//sum记录桥的总数
int head[MAX],dfn[MAX],low[MAX];
int deep[MAX],fa[MAX],pre[MAX],stack[MAX];
struct Edge{
int v,next;
Edge(){}
Edge(int V,int NEXT):v(V),next(NEXT){}
}edge[MAX*4];
void Init(int num){
for(int i=0;i<=num;++i)head[i]=-1,deep[i]=dfn[i]=0;
size=top=index=sum=0;
}
void InsertEdge(int u,int v){
edge[size]=Edge(v,head[u]);
head[u]=size++;
}
void dfs(int u,int father,int k){
deep[u]=k;
pre[u]=u;
for(int i=head[u];i != -1;i=edge[i].next){
int v=edge[i].v;
if(v == father)continue;
dfs(v,u,k+1);
fa[v]=u;
++sum;
}
}
int findset(int v){
if(v != pre[v])pre[v]=findset(pre[v]);
return pre[v];
}
void lca(int u,int v){
u=findset(u),v=findset(v);
top=0;
while(u != v){
if(deep[u]>deep[v])stack[++top]=u,u=findset(fa[u]);
else stack[++top]=v,v=findset(fa[v]);
--sum;
}
while(top)pre[stack[top--]]=u;
}
void tarjan(int u,int father){
if(dfn[u])return;
dfn[u]=low[u]=++index;
stack[++top]=u;
bool flag=true;
for(int i=head[u];i != -1;i=edge[i].next){
int v=edge[i].v;
if(v == father && flag){flag=false;continue;}
tarjan(v,u);
low[u]=min(low[u],low[v]);
}
if(dfn[u] == low[u]){
while(stack[top] != u)low[stack[top--]]=low[u];
--top;
}
}
int main(){
int u,v,q,num=0;
while(~scanf("%d%d",&n,&m),n+m){
Init(n);
for(int i=0;i<m;++i){
scanf("%d%d",&uu[i],&vv[i]);
InsertEdge(uu[i],vv[i]);
InsertEdge(vv[i],uu[i]);
}
tarjan(1,-1);
for(int i=0;i<=n;++i)head[i]=-1;
size=0;
for(int i=0;i<m;++i){//缩点重建图
if(low[uu[i]] == low[vv[i]])continue;
InsertEdge(low[uu[i]],low[vv[i]]);
InsertEdge(low[vv[i]],low[uu[i]]);
}
dfs(low[1],-1,1);//对于缩点后的点求深度
printf("Case %d:\n",++num);
scanf("%d",&q);
while(q--){
scanf("%d%d",&u,&v);
lca(low[u],low[v]);
printf("%d\n",sum);
}
printf("\n");
}
return 0;
}
Followed by:
Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator