【Tarjan】【SCC】【拓扑排序】Graph practice T3 graph 题解

来源:互联网 发布:知美术馆电话 编辑:程序博客网 时间:2024/05/21 17:44

Problem 3. graph
Input file: graph.in
Output file: graph.out
Time limit: 1 second
jyb 给大家讲过强连通分量,强连通分量中的任意两点之间都可以互相到达。这个条件感觉很苛刻,大部分图
都不能满足。现在jyb 告诉你一个新的概念:单向连通图;如果有向图中,对于任意节点v1 和v2,至少存
在从v1 到v2 和从v2 到v1 的路径中的一条,则为单向连通图。现在给出若干个有向图,jyb 想问你它们是
不是单向连通图。
Input
第1 行,1 个整数T, 表示数据组数,对于每组数据:
第1 行,2 个整数n;m,表示点数和边数
接下来m 行,每行2 个整数u,v, 表示u 到v 有一条单向边。题目保证u! = v
Output
对于每组数据,如果是则输出”Yes”, 不是则输出”No”(均不含引号)
Sample
graph.in graph.out
2
3 2
1 3
2 3
3 2
1 2
2 3
No
Yes
Note
• 对于30% 的数据,1  n  100,1  m  n2
• 对于100% 的数据,1  T  5,1  n  30000,1  m  2  105。

Graph:tarjan求SCC+拓扑排序
tarjan缩点并查集也可以过

暴力做法:Floyd求任意两点连通性。(给了30%的分)
我们知道,对于在同一SCC中的两点,它们是互相可达的,这也意味着一个SCC中的所有点和其他点的连通性都是一样的,显然我们可以将原图缩点简化问题。经过tarjan缩点后,得到了一个DAG,我们很容易想到如果一个图“分叉”,那么分叉上的点肯定是互不可达的,所以原图必须是“一条链”。为什么对链打引号呢?是因为这条链不用很严格,比如1->2 2->3 3->4 1->4 2->4这样的图也是满足的,且可能还有重边,所以只用入度出度去判断的方法容易出错,dfs去走一条链的办法也比较麻烦(我没想出有什么简单的办法)。我们利用拓扑排序,若一直都是一个入度为0的点(队中至多有一个点),那么就是满足题意的。
Ps:可以先写一个floyd来对拍(因为时间代价很低)
时间复杂度O(n+m)

#include <iostream>#include <cstdio>#include <vector>#include <queue>#include <cstring>#include <string>#define INF 2100000000#define clr(x) memset(x,0,sizeof(x))#define ms(a,x) memset(x,a,sizeof(x))using namespace std;const int maxm = 2e5+5;const int maxn = 30005;int n,m,t,frm,to;int fa[maxn];template <class T> inline void read(T &x) {    int flag = 1; x = 0;    char ch = getchar();    while(ch <  '0' || ch >  '9') { if(ch == '-')  flag = -1; ch = getchar(); }    while(ch >= '0' && ch <= '9') { x = (x<<1)+(x<<3)+ch-'0'; ch = getchar(); }    x *= flag;}bool find(int x, int aim) {    if(x == aim) return 0;    if(fa[x] == x) return 1;    if(x != aim) return find(fa[x], aim);}inline void unionn(int r1, int r2) { fa[r1] = r2; }inline bool check() {    for(int i = 1; i <= n; i++)        for(int j = i; j <= n; j++)            if(find(i, j) && find(j, i)) return 1;    return 0;}int main() {    freopen("graph.in","r",stdin);    freopen("graph.out","w",stdout);    read(t);    while(t--){        read(n); read(m); clr(fa);        for(int i = 1; i <= n; i++) fa[i] = i;        for(int i = 1; i <= m; i++) read(frm), read(to), unionn(frm, to);        if(check()) printf("No\n");        else printf("Yes\n");    }    return 0;}
0 0
原创粉丝点击