• POJ 1236 SCC+缩点


    题意:一张有向图,一问至少给几个点发送软件,才能让所有点都能收到软件;二问是至少添加几条边才能让整个图是一个连通分量;

    分析:一般求连通分量都会求缩点,在这里缩点之后,生成一张新的图,在新的图中求每一个点的出度,入度。答案就是sum(入度=0),max(sum(出度 == 0),sum(入度 == 0));

    注意:如果整张图本来就是一个强连通分量,需要特判。因为它出度,入度都等于0,即max(1,1) = 1,但是实际上不用再补充边了,应该是0,按照上面的分析答案就错了。

      1 ///POJ1236
      2 ///时间复杂度也是O(N+M)
      3 #include <stdio.h>
      4 #include <string.h>
      5 #include <vector>
      6 #include <stack>
      7 #include <iostream>
      8 #define repu(i,a,b) for(int i=a;i<b;i++)
      9 using namespace std;
     10 #define N 105            /// 题目中可能的最大点数
     11 stack<int>sta;            /// 存储已遍历的结点
     12 vector<int>gra[N];        /// 邻接表表示图
     13 int dfn[N];        /// 深度优先搜索访问次序
     14 int low[N];        /// 能追溯到的最早的次序
     15 int InStack[N];
     16 /// 检查是否在栈中(2:在栈中,1:已访问,且不在栈中,0:不在)
     17 vector<int> Component[N]; /// 获得强连通分量结果
     18 int InComponent[N];          /// 记录每个点在第几号强连通分量里
     19 int Index,ComponentNumber;/// 索引号,强连通分量个数
     20 int n, m;          /// 点数,边数
     21 int d[N][N],chu[N],ru[N];
     22 
     23 void init()///清空容器,数组
     24 {
     25     memset(dfn, 0, sizeof(dfn));
     26     memset(low, 0, sizeof(low));
     27     memset(chu, 0, sizeof(chu));
     28     memset(ru, 0, sizeof(ru));
     29     memset(InStack, 0, sizeof(InStack));
     30     Index = ComponentNumber = 0;
     31     for (int i = 1; i <= n; ++ i)
     32     {
     33         gra[i].clear();
     34         Component[i].clear();
     35     }
     36     repu(i,1,n+1)
     37     repu(j,1,n+1)
     38     d[i][j] = 0;
     39     while(!sta.empty())
     40         sta.pop();
     41 }
     42 void tarjan(int u)
     43 {
     44     InStack[u] = 2;
     45     low[u] = dfn[u] = ++ Index;
     46     sta.push(u);///寻找u所在的强连通分量
     47     for (int i = 0; i < gra[u].size(); ++ i)
     48     {
     49         int t = gra[u][i];
     50         if (dfn[t] == 0)///不在的继续递归
     51         {
     52             tarjan(t);///递归到头了就
     53             low[u] = min(low[u], low[t]);
     54         }
     55         else if (InStack[t] == 2)///在栈里
     56         {
     57             low[u] = min(low[u], dfn[t]);
     58         }
     59     }
     60     if(low[u] == dfn[u])///sta出栈就是一个强连通分量的
     61     {
     62         ++ComponentNumber;///强连通分量个数
     63         while (!sta.empty())
     64         {
     65             int j = sta.top();
     66             sta.pop();
     67             InStack[j] = 1;///已访问但不在栈中
     68             Component[ComponentNumber].push_back(j);
     69             ///用vector存储第ComponentNumber个强连通分量
     70             InComponent[j]=ComponentNumber;
     71             ///记录每个点在第几号强连通分量里
     72             if (j == u)
     73                 break;
     74         }
     75     }
     76 }
     77 void input()
     78 {
     79     repu(i,1,n+1)
     80     {
     81         while(scanf("%d",&m) &&m)
     82             d[i][m] = 1,gra[i].push_back(m);///有向图才有强连通分量
     83     }
     84 }
     85 
     86 void solve(void)
     87 {
     88     for(int i=1; i<=n; i++)
     89         if(!dfn[i])
     90             tarjan(i);
     91     if(ComponentNumber == 1)
     92     {
     93         printf("1
    0
    ");
     94         return;
     95     }
     96     ///缩点
     97     for(int i=1; i<=ComponentNumber; i++)
     98     {
     99         for(int j = 0; j < Component[i].size(); j++)
    100         {
    101             for(int k = 1; k<=n; k++)
    102             {
    103                 if(d[k][Component[i][j]] && k != Component[i][j])
    104                 {
    105                     int s = InComponent[k];
    106                     int t = InComponent[Component[i][j]];
    107                     if(s!=t)
    108                     {
    109                         chu[s]++;
    110                         ru[t]++;
    111                     }
    112                 }
    113             }
    114         }
    115     }
    116     int sum = 0,num = 0;
    117     for(int i=1; i<=ComponentNumber; i++)
    118     {
    119         if(!chu[i])
    120             sum++;
    121         if(!ru[i])
    122             num++;
    123     }
    124     printf("%d
    %d
    ",num,max(sum,num));
    125 }
    126 
    127 int main()
    128 {
    129     while(~scanf("%d",&n))
    130     {
    131         init();
    132         input();
    133         solve();
    134         /*每一个强连通分量的具体数字
    135         for(int i = 1; i <= ComponentNumber; i++)
    136         {
    137             for(int j = 0; j < Component[i].size(); j++)
    138                 if(!j)
    139                     cout << Component[i][j];
    140                 else
    141                     cout <<"-->"<< Component[i][j];
    142             cout<<endl;
    143         }
    144         */
    145     }
    146     return 0;
    147 }
    View Code

     

  • 相关阅读:
    火爆全网的合成大西瓜小游戏魔改版大全
    [Qt]cmake下Qt隐藏console的窗口
    c# WebBrowser控制台输出执行js后的网页内容
    好的编程习惯是减少bug最有效的方法
    创建线程 出现SIGSEGV crash
    linux下进程创建/僵尸进程/孤儿进程
    C++实现不可被继承的类
    程序并发概述
    C++ vector实现原理
    C++深拷贝和浅拷贝
  • 原文地址:https://www.cnblogs.com/ACMERY/p/4681803.html
Copyright © 2020-2023  润新知