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

poj 2762 Going from u to v or from v to u?(强连通分量+缩点重构图+拓扑排序)

2013-08-11 20:23 483 查看
http://poj.org/problem?id=2762

Going from u to v or from v to u?

Time Limit: 2000MSMemory Limit: 65536K
Total Submissions: 12733Accepted: 3286
Description

In order to make their sons brave, Jiajia and Wind take them to a big cave. The cave has n rooms, and one-way corridors connecting some rooms. Each time, Wind choose two rooms x and y, and ask one of their little sons go from one to the other. The son can either go from x to y, or from y to x. Wind promised that her tasks are all possible, but she actually doesn't know how to decide if a task is possible. To make her life easier, Jiajia decided to choose a cave in which every pair of rooms is a possible task. Given a cave, can you tell Jiajia whether Wind can randomly choose two rooms without worrying about anything?
Input

The first line contains a single integer T, the number of test cases. And followed T cases.
The first line for each case contains two integers n, m(0 < n < 1001,m < 6000), the number of rooms and corridors in the cave. The next m lines each contains two integers u and v, indicating that there is a corridor connecting room u and room v directly.
Output

The output should contain T lines. Write 'Yes' if the cave has the property stated above, or 'No' otherwise.
Sample Input

1
3 3
1 2
2 3
3 1

Sample Output

Yes

Source

POJ Monthly--2006.02.26,zgl & twb

【题解】:
  
  这题题目大概意思就是说 判断两个点之间是不是能够走通,u到v 或者 v到u 都行,这题开始题目意思都理解错了,一开始以为就是一个判断强连通的题;
  先求强连通分量;
  然后将强连通分量缩点,重构图;
  强连通分量内部的点肯定是可以两两到的,所以可以不用管了;
  缩点后的图,然后进行拓扑排序,如果有两个及以上的点的入度为0,那么他们之间肯定是不可达的,所以不符合
  如图:
  


【code】:

/**
Judge Status:Accepted     Memory:4896K
Time:485MS        Language:G++
Code Lenght:2940B   Author:cj
*/

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<stack>

using namespace std;
#define N 1010
#define M 6060

struct Edge
{
int v;
int next;
int u;
}edge[M];  //M  开始传的N  RE

int head
,edge_cnt;//这一行变量是构造边的

int pre
,lowlink
,sccno
,dfs_cnt,scc_cnt;  //这两行是Tarjan算法求强连通分量用的
stack<int> stk;

vector<int> G
;  //缩点重构图用的邻接链表
int in
,mark

;  //入度统计,以及重复边的标记

void init()
{
memset(head,-1,sizeof(head));
edge_cnt = 0;
}

void addEdge(int a,int b)
{
edge[edge_cnt].v = b;
edge[edge_cnt].next = head[a];
edge[edge_cnt].u = a;   //这里记录a,重构图用,方便遍历所有边
head[a] = edge_cnt++;
}

void Tarjan(int u)  //强连通分量
{
stk.push(u);
pre[u] = lowlink[u] = ++dfs_cnt;
int i;
for(i=head[u];i!=-1;i=edge[i].next)
{
int v = edge[i].v;
if(!pre[v])
{
Tarjan(v);
lowlink[u] = min(lowlink[u],lowlink[v]);
}
else if(!sccno[v])
{
lowlink[u] = min(lowlink[u],pre[v]);
}
}
if(pre[u]==lowlink[u])
{
scc_cnt++;
int x;
do
{
x = stk.top();
stk.pop();
sccno[x] = scc_cnt;  //sccno[x]表示下标为x的节点所在的第几个强连通分量
}while(x!=u);
}
}

void findscc(int n)
{
memset(pre,0,sizeof(pre));
memset(lowlink,0,sizeof(lowlink));
memset(sccno,0,sizeof(sccno));
dfs_cnt = scc_cnt = 0;
while(!stk.empty()) //初始化 以防万一
{
stk.pop();
}
int i;
for(i=1;i<=n;i++)   if(!pre[i]) Tarjan(i);
}

void getNewMap()  //重构缩点后的图,存入邻接链表G中
{
int i,j;
for(i=0;i<=scc_cnt;i++)
{
G[i].clear();
in[i] = 0;
}
memset(mark,0,sizeof(mark));
for(i=0;i<edge_cnt;i++)
{
int v = edge[i].v;
int u = edge[i].u;
if(sccno[u]!=sccno[v])
{
if(!mark[u][v])  //重复边标记
{
G[sccno[u]].push_back(sccno[v]);
in[sccno[v]]++;  //入度统计
}
mark[u][v] = 1;
}
}
}

int cntInid()  //计算入度为0的位置,以及是不是一个
{
int i,cnt=0,id=0;
for(i=1;i<=scc_cnt;i++)
{
if(!in[i])
{
cnt++;
id = i;
}
}
if(cnt==1)
return id;
return 0;
}

int isOK()  //用拓扑排序判断是否可行
{
int id = cntInid();
if(!id)  return 0;
int i;
in[id] = -1;
for(i=0;i<G[id].size();i++)
{
in[G[id][i]]--;
}
if(G[id].size()>0)  return isOK();
return 1;
}

int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
scanf("%d%d",&n,&m);
int i;
init();
for(i=0;i<m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
addEdge(a,b);
}
findscc(n);  //求强连通分量
if(scc_cnt==1)  //如果只有一个那么肯定可行
{
puts("Yes");
continue;
}
getNewMap();  //用强连通分量缩点,重构图
if(isOK())  puts("Yes"); //拓扑排序判断
else  puts("No");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: