【连通图|单连通】POJ-2762 Going from u to v or from v to u?

19 篇文章 0 订阅
14 篇文章 0 订阅
Going from u to v or from v to u?
Time Limit: 2000MS Memory Limit: 65536K
   

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
————————————————————————————————————————————————————————————————————————————————————————————————
题意:给出一个有向图,问该图是否是单连通图。
思路:单连通图:图中任意两点之间存在有向路径。
先求强连通分量,然后缩点,最后拓扑排序。
如果图中所有点可以排成一条单链,那么该图就是单连通图。
缩点之后整张图会变成一张DAG(有向无环图)
怎么求DAG上的单连通呢?对于任意一个点i,有a个点可以走到i,从i可以走到b个点,那么这a个点的拓扑序在i的前面,这b个点的拓扑序在i的后面。
依此类推,除了i点之外的所有点,要么在前面,要么在后面。允许有一个起点和一个终点。特别的,如果该图缩成了一个点,那么就是一个环。(样例)
代码如下:
/*
 * ID: j.sure.1
 * PROG:
 * LANG: C++
 */
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <climits>
#include <iostream>
#define Mem(f, x) memset(f, x, sizeof(f))
#define PB push_back
#define LL long long
using namespace std;
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
/****************************************/
const int N = 1005, M = 6005;
struct Edge {
    int v, next;
    Edge(){}
    Edge(int _v, int _next):
        v(_v), next(_next){}
}e[M];
int tot, deep, scc_cnt, n, m;
int scc_id[N], dfn[N], head[N], in[N], line[M][2];
stack <int> s;

void __init__()
{
    Mem(head, -1);
    Mem(in, 0);
    Mem(dfn, 0);
    Mem(scc_id, 0);
    tot = deep = scc_cnt = 0;
}

void add(int u, int v)
{
    e[tot] = Edge(v, head[u]);
    head[u] = tot++;
}

int dfs(int u)
{
    int lowu = dfn[u] = ++deep;
    s.push(u);
    for(int i = head[u]; ~i; i = e[i].next) {
        int v = e[i].v;
        if(!dfn[v]) {
            int lowv = dfs(v);
            lowu = min(lowu, lowv);
        }
        else if(!scc_id[v]) lowu = min(lowu, dfn[v]);
    }
    if(lowu == dfn[u]) {
        scc_cnt++;
        while(1) {
            int x = s.top(); s.pop();
            scc_id[x] = scc_cnt;
            if(x == u) break;
        }
    }
    return lowu;
}

bool judge()
{
    int u;
    bool fir = false;
    for(int i = 1; i <= scc_cnt; i++) {
        if(!in[i]) {
            if(fir) return false;
            u = i;
            fir = true;
        }
    }
    int num = scc_cnt;
    while(num--) {
        fir = false;
        for(int i = head[u]; ~i; i = e[i].next) {
            int v = e[i].v;
            in[v]--;
            if(!in[v]) {
                if(fir) return false;
                u = v;
                fir = true;
            }
        }
    }
    return true;
}

int main()
{
#ifdef J_Sure
    freopen("000.in", "r", stdin);
    //freopen("999.out", "w", stdout);
#endif
    int T;
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &m);
        __init__();
        for(int i = 0; i < m; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            u--; v--;
            line[i][0] = u; line[i][1] = v;
            add(u, v);
        }
        //求scc
        for(int i = 0; i < n; i++) {
            if(!dfn[i]) dfs(i);
        }
        //缩点并求拓扑序
        Mem(head, -1);
        tot = 0;
        for(int i = 0; i < m; i++) {
            int u = scc_id[line[i][0]], v = scc_id[line[i][1]];
            if(u != v) {
                add(u, v);//注意,从1开始的哦
                in[v]++;
            }
        }
        if(judge()) puts("Yes");
        else puts("No");
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值