18.11.08 POJ 2762 Going from u to v or from v to u?(强连通+缩点+拓扑排序)

描述

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?

输入

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.输出The output should contain T lines. Write 'Yes' if the cave has the property stated above, or 'No' otherwise.

样例输入

1
3 3
1 2
2 3
3 1

样例输出

Yes
  1 #include <iostream>
  2 #include <string.h>
  3 #include <algorithm>
  4 #include <stack>
  5 #include <string>
  6 #include <math.h>
  7 #include <queue>
  8 #include <stdio.h>
  9 #include <string.h>
 10 #include <vector>
 11 #include <fstream>
 12 #include <set>
 13 
 14 using namespace std;
 15 
 16 const int maxn = 1005;
 17 vector<vector<int>>G(maxn);
 18 vector<set<int>>DAG(maxn);
 19 int dfn[maxn], low[maxn],father[maxn],colorP[maxn];
 20 bool route[maxn];
 21 int to[maxn];
 22 int ncount = 1, n, m, color;
 23 stack<int>p;
 24 
 25 void tarjan(int u,int father) {
 26     route[u] = true;
 27     p.push(u);
 28     low[u] = dfn[u] = ncount++;
 29     int l = G[u].size();
 30     for (int i = 0; i < l; i++) {
 31         int next = G[u][i];
 32         if (!dfn[next])
 33             tarjan(next, u);
 34         else if(route[next])
 35             low[u] = min(low[u], low[next]);
 36     }
 37     if (dfn[u] == low[u]) {
 38         int v = 0;
 39         ++color;
 40         while (v != u) {
 41             v = p.top();
 42             p.pop();
 43             colorP[v] = color;
 44         }
 45     }
 46     route[u] = false;
 47 }
 48 
 49 bool top() {
 50         int id, sum = 0;
 51         for (int i = 1; i <= color; i++) {
 52             if (to[i] == 0) {
 53                 id = i;
 54                 sum++;
 55             }
 56         }
 57         while (sum!=0)
 58         {
 59             if (sum > 1)
 60                 return false;
 61             sum = 0;
 62             set<int>::iterator i1 = DAG[id].begin(), i2 = DAG[id].end();
 63             for (; i1 != i2; i1++)
 64             {
 65                 to[*i1]--;
 66                 if (to[*i1] == 0) {
 67                     id = *i1;
 68                     sum++;
 69                 }
 70             }
 71         }
 72         return true;
 73 }
 74 
 75 void calculate() {
 76     for (int i = 1; i <= n; i++) {
 77         int size = G[i].size();
 78         for (int j = 0; j < size; j++) {
 79             int v = G[i][j];
 80             if (colorP[v] != colorP[i])
 81             {
 82                 DAG[i].insert(colorP[v]);
 83                 to[colorP[v]]++;
 84             }
 85         }
 86     }
 87     if (top())
 88         printf("Yes\n");
 89     else
 90         printf("No\n");
 91 }
 92 
 93 void init() {
 94     int kase;
 95     scanf("%d", &kase);
 96     while (kase--)
 97     {
 98         ncount = 1,n=0,m=0,color=0;
 99         memset(to, 0, sizeof(to));
100         memset(dfn, 0, sizeof(to));
101         memset(low, 0, sizeof(to));
102         memset(father, 0, sizeof(to));
103         memset(colorP, 0, sizeof(to));
104         G = vector<vector<int>>(maxn);
105         DAG = vector<set<int>>(maxn);
106         scanf("%d%d", &n, &m);
107         while (m--) {
108             int from, to;
109             scanf("%d%d", &from, &to);
110             G[from].push_back(to);
111             father[to] = from;
112         }
113         for (int i = 1; i <= n; i++) {
114             if (!dfn[i])
115                 tarjan(i, father[i]);
116         }
117         calculate();
118     }
119 }
120 
121 int main()
122 {
123     init();
124     return 0;
125 }
View Code

这道题给的数据也相当水,比较迷的是我在openjudge上跑了1ms,在POJ永远TLE

属于玄学过的,之后再到POJ跑跑看(我说的之后再看看好像就没看过……唉……)

思路是拓扑排序,首先是确定对有向无环图来说符合两点两两相通的情况必须是只有一个点入度为0且只有一个点出度为0并且没有分叉点

不知道老师课上有没有讲过,网上的参考,贴一下

 

如果DAG中,有2个或2个以上的点的入度为0,那么这个DAG就是No,因为这说明有两个点是无法“进去”的,没有点能“进去”U,也没有点能“进去”V,那么这两个点肯定互相不能“进去”,即到达

 

如果DAG中,有2个或2个以上的点的出度为0,那么这个DAG就是No,因为说明这两个点是无法“出去的”。

 

反证法,点U和V,它们出度都是0,假设它们满足题目条件,从U能到V,或者从V能到U

 

1.因为点U出度为0,所以无法“出去”,它肯定无法到达V

 

2.因为点V出度为0,所以无法“出去”,它肯定无法到达U

 

3.综上,点U无法到达V,点V无法到达点U,与假设矛盾,所以与题目不成立

 

 

 

那么什么最后一个问题,如果这个DAG,入度为0的点的个数 <= 1 , 出度为0的点的个数 <= 1 , 它就一定Yes吗?

 

这个就比较容易想了,首先,1个DAG中,不可能所有点都有入度,即入度为0的点个数为0,是不可能发生的。同样的,可能所有点都有出度,即出度为0的点个数为0,是不可能发生的

 

那剩下的情况就是,1个点入度为0为u,1个点出度为0为v。这个图,呈现一个“橄榄形”。如果从点u走到点v,能经过所有的点,那么就是Yes,否则是No。因为无法经过所有的点的话,说明图中出现了“分叉”,这种“分叉”必定导致两个点互相不可达。而从u到v,经过所有点,其实就是把这个DAG变成了一条链,就是判断这个DAG是否存在一条链贯穿所有点

 

 

 

怎么判断链呢?可以转化为拓扑排序,或者DP最长路

 

拓扑:拓扑排序可能有多种结果,但是如果是一个最长链,结果则是唯一的,结果要唯一,其实就是从初始化开始,到后面的任何一次删弧入队操作,都是保证了每次都只有一个元素入队,即永远只有一个元素的入度为0,如果中途有一次出现了有两个点入度为0,那么其实代表出现了一种“分叉”

 

而且拓扑排序可以综合掉前面的情况,不需要特判DAG有几个点入度为0,出度为0,直接拓扑,在拓扑过程就已经判断了

来自https://www.cnblogs.com/scau20110726/archive/2013/05/23/3094495.html

 

转载于:https://www.cnblogs.com/yalphait/p/9927366.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值