• poj 2762 Going from u to v or from v to u?(强连通分量+缩点重构图+拓扑排序)


    http://poj.org/problem?id=2762

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

    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

    Source

     
    【题解】:
      
      这题题目大概意思就是说 判断两个点之间是不是能够走通,u到v 或者 v到u 都行,这题开始题目意思都理解错了,一开始以为就是一个判断强连通的题;
      先求强连通分量;
      然后将强连通分量缩点,重构图;
      强连通分量内部的点肯定是可以两两到的,所以可以不用管了;
      缩点后的图,然后进行拓扑排序,如果有两个及以上的点的入度为0,那么他们之间肯定是不可达的,所以不符合
      如图:
      
    【code】:
      1 /**
      2 Judge Status:Accepted     Memory:4896K
      3 Time:485MS        Language:G++
      4 Code Lenght:2940B   Author:cj
      5 */
      6 
      7 #include<iostream>
      8 #include<algorithm>
      9 #include<stdio.h>
     10 #include<string.h>
     11 #include<vector>
     12 #include<stack>
     13 
     14 using namespace std;
     15 #define N 1010
     16 #define M 6060
     17 
     18 struct Edge
     19 {
     20     int v;
     21     int next;
     22     int u;
     23 }edge[M];  //M  开始传的N  RE
     24 
     25 int head[N],edge_cnt;//这一行变量是构造边的
     26 
     27 int pre[N],lowlink[N],sccno[N],dfs_cnt,scc_cnt;  //这两行是Tarjan算法求强连通分量用的
     28 stack<int> stk;
     29 
     30 vector<int> G[N];  //缩点重构图用的邻接链表
     31 int in[N],mark[N][N];  //入度统计,以及重复边的标记
     32 
     33 void init()
     34 {
     35     memset(head,-1,sizeof(head));
     36     edge_cnt = 0;
     37 }
     38 
     39 void addEdge(int a,int b)
     40 {
     41     edge[edge_cnt].v = b;
     42     edge[edge_cnt].next = head[a];
     43     edge[edge_cnt].u = a;   //这里记录a,重构图用,方便遍历所有边
     44     head[a] = edge_cnt++;
     45 }
     46 
     47 void Tarjan(int u)  //强连通分量
     48 {
     49     stk.push(u);
     50     pre[u] = lowlink[u] = ++dfs_cnt;
     51     int i;
     52     for(i=head[u];i!=-1;i=edge[i].next)
     53     {
     54         int v = edge[i].v;
     55         if(!pre[v])
     56         {
     57             Tarjan(v);
     58             lowlink[u] = min(lowlink[u],lowlink[v]);
     59         }
     60         else if(!sccno[v])
     61         {
     62             lowlink[u] = min(lowlink[u],pre[v]);
     63         }
     64     }
     65     if(pre[u]==lowlink[u])
     66     {
     67         scc_cnt++;
     68         int x;
     69         do
     70         {
     71             x = stk.top();
     72             stk.pop();
     73             sccno[x] = scc_cnt;  //sccno[x]表示下标为x的节点所在的第几个强连通分量
     74         }while(x!=u);
     75     }
     76 }
     77 
     78 void findscc(int n)
     79 {
     80     memset(pre,0,sizeof(pre));
     81     memset(lowlink,0,sizeof(lowlink));
     82     memset(sccno,0,sizeof(sccno));
     83     dfs_cnt = scc_cnt = 0;
     84     while(!stk.empty()) //初始化 以防万一
     85     {
     86         stk.pop();
     87     }
     88     int i;
     89     for(i=1;i<=n;i++)   if(!pre[i]) Tarjan(i);
     90 }
     91 
     92 void getNewMap()  //重构缩点后的图,存入邻接链表G中
     93 {
     94     int i,j;
     95     for(i=0;i<=scc_cnt;i++)
     96     {
     97         G[i].clear();
     98         in[i] = 0;
     99     }
    100     memset(mark,0,sizeof(mark));
    101     for(i=0;i<edge_cnt;i++)
    102     {
    103         int v = edge[i].v;
    104         int u = edge[i].u;
    105         if(sccno[u]!=sccno[v])
    106         {
    107             if(!mark[u][v])  //重复边标记
    108             {
    109                 G[sccno[u]].push_back(sccno[v]);
    110                 in[sccno[v]]++;  //入度统计
    111             }
    112             mark[u][v] = 1;
    113         }
    114     }
    115 }
    116 
    117 int cntInid()  //计算入度为0的位置,以及是不是一个
    118 {
    119     int i,cnt=0,id=0;
    120     for(i=1;i<=scc_cnt;i++)
    121     {
    122         if(!in[i])
    123         {
    124             cnt++;
    125             id = i;
    126         }
    127     }
    128     if(cnt==1)
    129         return id;
    130     return 0;
    131 }
    132 
    133 int isOK()  //用拓扑排序判断是否可行
    134 {
    135     int id = cntInid();
    136     if(!id)  return 0;
    137     int i;
    138     in[id] = -1;
    139     for(i=0;i<G[id].size();i++)
    140     {
    141         in[G[id][i]]--;
    142     }
    143     if(G[id].size()>0)  return isOK();
    144     return 1;
    145 }
    146 
    147 int main()
    148 {
    149     int t;
    150     scanf("%d",&t);
    151     while(t--)
    152     {
    153         int n,m;
    154         scanf("%d%d",&n,&m);
    155         int i;
    156         init();
    157         for(i=0;i<m;i++)
    158         {
    159             int a,b;
    160             scanf("%d%d",&a,&b);
    161             addEdge(a,b);
    162         }
    163         findscc(n);  //求强连通分量
    164         if(scc_cnt==1)  //如果只有一个那么肯定可行
    165         {
    166             puts("Yes");
    167             continue;
    168         }
    169         getNewMap();  //用强连通分量缩点,重构图
    170         if(isOK())  puts("Yes"); //拓扑排序判断
    171         else  puts("No");
    172     }
    173     return 0;
    174 }
  • 相关阅读:
    opengl画不出直线 线段 坐标轴 却能画出其他图形的坑
    c++多个文件中共用一个全局变量 变量跨文件使用
    关于c# winform 键盘响应右边键盘消息响应事件的上下左右方向键没有反应
    关于c#winform用sharpGL(OpenGL)绘制不出图形,绘制窗口是个黑框的坑
    C# winform用sharpGL(OpenGl)解析读取3D模型obj
    关于C#界面开发winform与SharpGL结合鼠标只在OpenGLControl绘图区域显示坐标移动消息响应(c#鼠标单独在某个控件上的消息响应)
    关于MFC与OpenGL结合绘图区域用鼠标来控制图形的移动的坑
    bullet物理引擎与OpenGL结合 导入3D模型进行碰撞检测 以及画三角网格的坑
    OpenGl 导入读取多个3D模型 并且添加鼠标控制移动旋转
    OpenGl 实现鼠标分别移动多个物体图形 ----------移动一个物体另外一个物体不动--读取多个3d模型操作的前期踏脚石
  • 原文地址:https://www.cnblogs.com/crazyapple/p/3251852.html
Copyright © 2020-2023  润新知