POJ 2762 Going from u to v or from v to u?
题意:有n个山洞m条路,问任意两点x,y能否存在从x到y或者从y到x。
思路:
1、注意是或而不是和,所以“缩点”后,由于“缩点”内的点相互可达,所以不需要管“缩点”内的点。注意,不是判断强连通的数量为1,而是判断是否是弱连通。
2、如果两点不可达那么在拓扑排序时,该两点谁也不是谁的前驱和后继,所以在拓扑排序时只要同时出现至少两个入度为0的点,那么这些点一定互不可达,所以只要判断拓扑的方式是否唯一即可。
第一种方法:只要用拓扑判断入度为0的点是否为1个,如果有多个,就出现在分叉,不可能从x到y。
第二种方法:从入度为0的点DFS搜索最长能到达的路径如果路径长度等于点数,说明可以从源点访问完所有点。
知识充电:
强连通图:在有向图中, 若对于每一对顶点v1和v2, 都存在一条从v1到v2和从v2到v1的路径,则称此图是强连通图.
弱连通图:将有向图的所有的有向边替换为无向边,所得到的图称为原图的基图。如果一个有向图的基图是连通图,则有向图是弱连通图。
单向连通图:如果有向图中,对于任意节点v1和v2,至少存在从v1到v2和从v2到v1的路径中的一条,则原图为单向连通图。
三者之间的关系是,强连通图必然是单向连通的,单向连通图必然是弱连通图。
CODE:
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
using
namespace std;
#define MAXN 50010
#define MAXM 100010
struct Edge
{
int v, next;
}edge[MAXM], edge2[MAXM];
int first[MAXN], first2[MAXN],stack[MAXN], ins[MAXN], dfn[MAXN], low[MAXN];
int belong[MAXM];
int ind[MAXN], outd[MAXN], topo[MAXN];
int n, m;
int cnt, cnt2;
int scnt, top, tot;
void init()
{
cnt =
0, cnt2 =
0;
scnt = top = tot =
0;
memset(dfn,
0,
sizeof(dfn));
memset(first, -
1,
sizeof(first));
memset(first2, -
1,
sizeof(first2));
memset(ins,
0,
sizeof(ins));
memset(ind,
0,
sizeof(ind));
//
memset(outd, 0, sizeof(outd));
//
memset(topo, 0, sizeof(topo));
}
void read_graph(
int u,
int v)
{
edge[cnt].v = v;
edge[cnt].next = first[u];
first[u] = cnt++;
}
void read_graph2(
int u,
int v)
//
重构图
{
edge2[cnt2].v = v;
edge2[cnt2].next = first2[u], first2[u] = cnt2++;
}
void dfs(
int u)
{
int v;
dfn[u] = low[u] = ++tot;
ins[u] =
1;
stack[top++] = u;
for(
int e = first[u]; e != -
1; e = edge[e].next)
{
v = edge[e].v;
if(!dfn[v])
{
dfs(v);
low[u] = min(low[u], low[v]);
}
else
if(ins[v])
{
low[u] = min(low[u], dfn[v]);
}
}
if(dfn[u] == low[u])
{
scnt++;
do
{
v = stack[--top];
belong[v] = scnt;
ins[v] =
0;
}
while(v != u);
}
}
void Tarjan()
{
for(
int v =
1; v <= n; v++)
if(!dfn[v])
dfs(v);
}
//
Tarjan
int toposort()
{
queue<
int> q;
int tot2 =
0;
for(
int i =
1; i <= scnt; i++)
if(!ind[i]) q.push(i);
if(q.size() >
1)
return
0;
while(!q.empty())
{
int x = q.front(); q.pop();
topo[++tot2] = x;
for(
int e = first2[x]; e != -
1; e = edge2[e].next)
{
int v = edge2[e].v;
if(--ind[v] ==
0)
{
q.push(v);
}
}
if(q.size() >
1)
return
0;
}
if(tot2 != scnt)
return
0;
else
return
1;
}
//
toposort
void solve()
{
Tarjan();
for(
int u =
1; u <= n; u++)
//
重构图
{
for(
int e = first[u]; e != -
1; e = edge[e].next)
{
int v = edge[e].v;
if(belong[u] != belong[v])
{
ind[belong[v]]++;
read_graph2(belong[u], belong[v]);
}
}
}
if(toposort()) printf(
"
Yes\n
");
else printf(
"
No\n
");
}
int main()
{
int T;
scanf(
"
%d
", &T);
while(T--)
{
init();
scanf(
"
%d%d
", &n, &m);
while(m--)
{
int u, v;
scanf(
"
%d%d
", &u, &v);
read_graph(u, v);
}
solve();
}
return
0;
}