您的位置:首页 > 编程语言 > Go语言

POJ2762 Going from u to v or from v to u?(判定单连通图:强连通分量+缩点+拓扑排序)

2016-01-24 18:25 507 查看
这道题要判断一张有向图是否是单连通图,即图中是否任意两点u和v都存在u到v或v到u的路径。

方法是,找出图中所有强连通分量,强连通分量上的点肯定也是满足单连通性的,然后对强连通分量进行缩点,缩点后就变成DAG。

现在问题就变成,如何判断DAG是否是单连通图——用拓扑排序——如果拓扑排序过程中出现1个以上入度为0的点那就不是单连通图,因为有2个入度0的点,那这两个点肯定都无法到达对方。

另外,注意题目没说给的图是连通的!。。

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define MAXN 1111
#define MAXM 6666
struct Edge{
int u,v,next;
}edge[MAXM];
int NE,head[MAXN];
void addEdge(int u,int v){
edge[NE].u=u; edge[NE].v=v; edge[NE].next=head[u];
head[u]=NE++;
}

int belong[MAXN],bn,stack[MAXN],top;
bool instack[MAXN];
int dn,dfn[MAXN],low[MAXN];
void dfs(int u){
dfn[u]=low[u]=++dn;
stack[++top]=u; instack[u]=1;
for(int i=head[u]; i!=-1; i=edge[i].next){
int v=edge[i].v;
if(dfn[v]==0){
dfs(v);
low[u]=min(low[u],low[v]);
}else if(instack[v]){
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u]){
int v; ++bn;
do{
v=stack[top--];
belong[v]=bn;
instack[v]=0;
}while(u!=v);
}
}

int deg[MAXN];
bool toposort(){
queue<int> que;
for(int i=1; i<=bn; ++i){
if(deg[i]==0) que.push(i);
}
if(que.size()>1) return 0;
while(!que.empty()){
int u=que.front(); que.pop();
for(int i=head[u]; i!=-1; i=edge[i].next){
int v=edge[i].v;
if(--deg[v]==0) que.push(v);
}
if(que.size()>1) return 0;
}
return 1;
}
int main(){
int t,n,m,a,b;
scanf("%d",&t);
while(t--){
NE=0;
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
while(m--){
scanf("%d%d",&a,&b);
addEdge(a,b);
}

top=bn=dn=0;
memset(instack,0,sizeof(instack));
memset(dfn,0,sizeof(dfn));
for(int i=1; i<=n; ++i){
if(dfn[i]==0) dfs(i);
}

int tmp=NE; NE=0;
memset(head,-1,sizeof(head));
memset(deg,0,sizeof(deg));
for(int i=0; i<tmp; ++i){
int u=belong[edge[i].u],v=belong[edge[i].v];
if(u==v) continue;
addEdge(u,v);
++deg[v];
}
if(toposort()) puts("Yes");
else puts("No");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: