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

poj 2762 Going from u to v or from v to u?

2010-10-21 16:51 260 查看
// poj 2762 Going from u to v or from v to u?
/*
题意: 判断一个有向图中是否任意两点都至少满足一点到另一点可达
题解: Robert Sedgewick著《C++算法--图算法》P179
PS: 由于作业比较多,做题时间有限,未做太多优化,望见谅
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int n,m;
int con[1010][1010],rcon[1010][1010]; //图和逆图
int id[1010],post[1010],pre[1010],cnt,scnt; //id标识强连分量,pre和post分别是前序后序编号
int r[1010][1010],tc[1010][1010];  //r是核心DAG,tc是其闭包

//图和逆图的两次遍历
void dfs(int con[][1010],int v,int flag){
id[v]=cnt;
for (int i=0;i<n;i++)
if (con[v][i] && id[i]==-1)
{
dfs(con,i,flag);
}
if (flag) post[scnt++]=v;
}

//求DAG的闭包
void tcR(int v){
pre[v] = scnt++;
for (int i=0;i<cnt;i++)
if (r[v][i]){
tc[v][i]=1;
if (pre[i]>pre[v]) continue;
if (pre[i]==-1) tcR(i);
for (int j=0;j<cnt;j++){
if (tc[i][j]){
tc[v][j]=1;
}
}
}
}

int main()
{
int t,a,b;
scanf("%d",&t);
while (t--){
memset(con,0,sizeof(con));
memset(rcon,0,sizeof(rcon));
memset(r,0,sizeof(r));
scanf("%d%d",&n,&m);
while (m--){
scanf("%d%d",&a,&b);
//printf("%d %d/n",a,b);
con[a-1][b-1]=1;
rcon[b-1][a-1]=1;
}

//算出原图顶点的后序编号
cnt=scnt=0;
memset(id,-1,sizeof(id));
memset(post,-1,sizeof(post));
for (int i=0;i<n;i++){
if (id[i]==-1){
dfs(con,i,1);
cnt++;
}
}

memset(id,-1,sizeof(id));

//按后序编号post的递减顺序再做一次DFS,进而求出核心DAG
cnt=0;
for (int i=n-1;i>=0;i--){
if (id[post[i]]==-1){
dfs(rcon,post[i],0);
cnt++;
}
}

if (cnt==1){
printf("Yes/n");
continue;
}

scnt=0;
//建立以强连通子图为顶点所形成的新图
for (int i=0;i<n;i++)
for (int j=0;j<n;j++)
if (con[i][j]) r[id[i]][id[j]]=1;

//求新图的闭包
memset(pre,-1,sizeof(pre));
memset(tc,0,sizeof(tc));
tcR(0);
bool flag = true;
for (int i=0;i<cnt && flag;i++)
for (int j=i+1;j<cnt;j++)
if (!tc[i][j] && !tc[j][i]) {
flag=false;
break;
}
if (flag) printf("Yes/n");
else printf("No/n");

}
system("pause");
return 0;
}
/*
5 4
1 2
2 3
2 4
4 5
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: