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

POJ2762-Going from u to v or from v to u?(有向图强连通分量缩点)

2017-03-31 18:51 495 查看
Going from u to v or from v to u?

Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 17556 Accepted: 4714
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

题意:有n个点和m条有向边,问对于每一对点(x,y)是不是都可以x走到y或y走到x

解题思路:先将每个强连通分量收缩为一个点,然后进行拓扑排序,看每次在栈中的是不是都只有一个点

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <functional>
#include <climits>

using namespace std;

#define LL long long
const int INF=0x3f3f3f3f;

const int N=1010;
int n, m;
struct Node
{
int v,nt;
} edge[N*100];
int s
,cnt;
int dfn
,low
,id
,dep;
bool vis
,instack
;
int graph

;
int in
;
int res;
stack<int>st;

void AddEdge(int u,int v)
{
edge[cnt].v=v;
edge[cnt].nt=s[u];
s[u]=cnt++;
}

void tarjan(int u)
{
st.push(u);
instack[u]=true;
vis[u]=true;
dfn[u]=low[u]=++dep;
for(int i=s[u]; ~i; i=edge[i].nt)
{
int v=edge[i].v;
if(!vis[v]) // 生成树的边.
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(instack[v])//在栈中,回边.
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u])//顶点u为根的子树是一个强连同块
{
int t;
do
{
id[t=st.top()]=res;
st.pop();
instack[t]=false; //low[t] = n;
}
while(t!=u);
res++;//强连通分量增加
}
}

void solve()
{
res=0,dep=0;
while(!st.empty()) st.pop();
memset(vis,0,sizeof vis);
memset(instack,0,sizeof instack);
for(int i=1; i<=n; i++)
if(!vis[i]) tarjan(i);
// Debug
/* for(int i = 1; i <= n; i++)
printf("dfn[%d] = %d, low[%d] = %d\n", i,dfn[i], i,low[i]);
for(int i = 1; i <= n; i++)
printf("id[%d] = %d\n", i, id[i] );*/
memset(graph,0,sizeof graph);
for(int u=1; u<=n; u++)
{
for(int i=s[u]; ~i; i=edge[i].nt)
{
int v=edge[i].v;
graph[id[u]][id[v]]=1;
}
}
memset(in,0,sizeof in);
memset(vis,0,sizeof vis);
while(!st.empty()) st.pop();
for(int i=0; i<res; i++)
{
for(int j=0; j<res; j++)
if(i!=j) in[i]+=graph[j][i];
if(in[i]==0) st.push(i),vis[i]=true;
}
bool flag=true;
while(!st.empty())
{
if(st.size()>1) {flag=false;break;}
int u=st.top();
st.pop();
vis[u]=false;
for(int v=0; v<res; v++)
{
if(graph[u][v])
{
if(u==v) continue;
in[v]-=graph[u][v];
if(in[v]==0&&!vis[v]) st.push(v),vis[v]=true;
}
}
}
puts(flag?"Yes":"No");
}

int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
memset(s,-1,sizeof s);
cnt=0;
for(int i=0; i<m; i++)
{
int u,v;
scanf("%d%d",&u,&v);
AddEdge(u,v);
}
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: