zoukankan      html  css  js  c++  java
  • POJ 2762--Going from u to v or from v to u?【scc缩点新建图 && 推断是否是弱连通图】

    Going from u to v or from v to u?
    Time Limit: 2000MS   Memory Limit: 65536K
    Total Submissions: 15755   Accepted: 4172

    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

    题意:是给出一些点,给出n个点和m条边,接着给出直接相连的边(注意是有向边),求解随意x,y两点间是否存在 x 可到达 y 或者y可
    到达x,假设随意x和y都满足这种条件,就输出"Yes", 否则输出"No".。

    注意。这里是 x 到达 y 或者 y 到达 x ,是或者不是并且 。!

    假设是“并且”的话。非常明显的是推断整个图是否为一个强连通分量(如题HDU 1296 , 题目解析)。但这题并非这样。


    本题应推断整个图是否为一个弱连通分量。

    正确思路:先求解出该有向图的强连通分量。然后依据求解出来的强连通分量进行缩点又一次建图

    问题转换为求解在新图中是否存在一条能走全然部的顶点的路径,这时能够对缩点后的新图进行拓扑排序,看拓扑排序能否够成功进行

    拓扑排序遵循条件
    一:新图不能有多于1个的入度为0的点,这是保证每一个点都有边相连。
    二:在拓扑排序遍历点u的过程中,若去掉与u相关的边后出现多于1个的入度为0的点,说明这些点仅仅能由u到达,而它们之间不存在可达路径。这时不满足弱连通,跳出。


    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <queue>
    #include <algorithm>
    #define maxn 10000 + 100
    #define maxm 100000 + 1000
    using namespace std;
    int n, m;
    struct node {
    	int u, v, next;
    };
    node edge[maxm];
    int head[maxn], cnt;
    int low[maxn], dfn[maxn];
    int dfs_clock;
    int Stack[maxn];
    bool Instack[maxn];
    int top;
    int Belong[maxn] , scc_clock;
    int in[maxn];
    vector<int>Map[maxn];
    
    void init(){
    	cnt = 0;
    	memset(head, -1, sizeof(head));
    }
    
    void addedge(int u, int v){
    	edge[cnt] = {u, v, head[u]};
    	head[u] = cnt++;
    }
    
    void getmap(){
        scanf("%d%d", &n, &m);
        while(m--){
            int a, b;
            scanf("%d%d", &a, &b);
            addedge(a, b);
        }
    }
    
    void tarjan(int u, int per){
        int v;
        low[u] = dfn[u] = ++dfs_clock;
        Stack[top++] = u;
        Instack[u] = true;
        for(int i = head[u]; i != -1; i = edge[i].next){
            v = edge[i].v;
            if(!dfn[v]){
                tarjan(v, u);
                low[u] = min(low[v], low[u]);
            }
            else if(Instack[v]){
                low[u] = min(low[u], dfn[v]);
            }
        }
        if(dfn[u] == low[u]){
            scc_clock++;
            do{
                v = Stack[--top];
                Instack[v] = false;
                Belong[v] = scc_clock;
            }while(u != v);
        }
    }
    
    void find(){
        memset(low, 0, sizeof(low));
        memset(dfn, 0, sizeof(dfn));
        memset(Instack, false, sizeof(Instack));
        memset(Belong, 0, sizeof(Belong));
        dfs_clock = scc_clock = top = 0;
        for(int i = 1; i <= n; ++i){
            if(!dfn[i])
                tarjan(i, i);
        }
    }
    
    void suodian(){
        for(int i = 1; i <= scc_clock; ++i){
            Map[i].clear();
            in[i] = 0;
        }
        for(int i = 0; i < cnt; ++i){
            int u = Belong[edge[i].u];
            int v = Belong[edge[i].v];
            if(u != v){
                Map[u].push_back(v);
                in[v]++;
            }
        }
    }
    
    void solve(){
        queue<int>q;
        int num = 0;
        for(int i = 1; i <= scc_clock; ++i){
            if(!in[i]){
                num++;
                q.push(i);
            }
            if(num > 1){
                printf("No
    ");
                return ;
            }
        }
        while(!q.empty()){
            int u = q.front();
            q.pop();
            num = 0;
            for(int i = 0; i < Map[u].size(); ++i){
                int v = Map[u][i];
                in[v]--;
                if(!in[v]){
                    num++;
                    //有两个或两个以上的分支。不是弱连通
                    if(num > 1){
                        printf("No
    ");
                        return ;
                    }
                    q.push(v);
                }
            }
        }
        printf("Yes
    ");
    }
    
    int main (){
        int T;
        scanf("%d", &T);
    	while(T--){
            init();
            getmap();
            find();
            suodian();
            solve();
    	}
    	return 0;
    }
    


  • 相关阅读:
    使用自制事务进行异常信息的记录:Autonomous transactionslog
    backup methodsexp and imp
    一个 SQL 同时验证帐号是否存在、密码是否正确
    使用存储过程进行分页:page by Procedure
    推荐一款类似于editplus的文本编辑工具:note++
    myeclipse8.5反编译插件的安装使用jdgui插件
    [转]JavaMail的使用之邮件发送 详解
    Thinking in java中内部类的例子。
    [转]tomcat6.0下的log4j日志文件配置过程
    127.X.X.X開頭的網路都是特殊用途的嗎!?
  • 原文地址:https://www.cnblogs.com/yfceshi/p/6923538.html
Copyright © 2011-2022 走看看