zoukankan      html  css  js  c++  java
  • POJ 1236 Network Of Schools (思维+强连通)

    <题目链接>

    题目大意:

    有N个学校,每个学校之间单向可以发送软件,现在给你一些学校之间的收发关系。问你下面两个问题:至少要给多少个学校发送软件才能使得最终所有学校都收到软件;至少要多加多少个关系才能使得向任意一个学校发送一套软件,每个学校都能收到软件。 

    解题分析:

    首先,对该图进行缩点,显然第一问问的就是,缩点后的入度为0的联通块的数量(因为这些点没有入度,必须人为的给它们软件,它们才能接收到软件);第二问,显然就是问至少要加多少条边,使得该图变为强连通图,强连通图有个条件,就是所有的点一定要有出度和入度,所以我们可以让没有出度的点连上没有入度的点,等到出度或者入度为0的点不存在时,再把出度或入度为0的点补完(不能自己连自己,因为题目要求的是最少需要多少条边,所以考虑最优情况),注意,当整张图为连通图时,它的出度和入度均为0,max(1,1)=1,但是实际上不需要补边,所以这种情况需要特判。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <string>
     4 #include <algorithm>
     5 #include <queue>
     6 using namespace std;
     7 
     8 const int M = 1e5 + 10;
     9 int n, m, u, v, tot, top, cnt, col;
    10 struct node {
    11     int v, next;
    12 } edge[M];
    13 int head[M], instack[M], stk[M];
    14 int dfn[M], low[M], belong[M],in[M],out[M];
    15 void init() {
    16     tot = cnt = top = col = 0;
    17     memset(stk, 0, sizeof(stk));
    18     memset(head, -1, sizeof(head));
    19     memset(dfn, 0, sizeof(dfn));
    20     memset(instack, 0, sizeof(instack));
    21 }
    22 void add(int u, int v) {
    23     edge[tot].v = v,edge[tot].next = head[u];
    24     head[u] = tot++;
    25 }
    26 void tarjan(int u) {
    27     dfn[u] = low[u] = ++col;    //col为遍历到该点的编号时间
    28     instack[u] = 1;    //标记该元素是否在栈里
    29     stk[top++] = u;
    30     for (int i = head[u] ; ~i ; i = edge[i].next) {
    31         int v = edge[i].u;        
    32         if (!dfn[v]) {
    33             tarjan(v);
    34             low[u] = min(low[u], low[v]);
    35         } 
    36         else if (instack[v]) low[u] = min(low[u], dfn[v]);
    37     }
    38     if (dfn[u] == low[u]) {
    39         cnt++;   //记录连通块的数量
    40         int tmp;
    41         do{
    42             tmp = stk[--top];
    43             instack[tmp] = 0;
    44             belong[tmp] = cnt;     //给该连通块中的点染色
    45         } while(tmp != u) ;
    46     }
    47 }
    48 void solve() {
    49     for (int i = 1 ; i <= n ; i++)
    50         if (!dfn[i]) tarjan(i);
    51 }
    52 int main() {
    53     while(scanf("%d", &n) != EOF) {
    54         init();
    55         memset(in, 0, sizeof(in));
    56         memset(out, 0, sizeof(out));
    57         for (int i = 1 ; i <= n ; i++) {
    58             int v;
    59             scanf("%d", &v);
    60             while(v) {
    61                 add(i, v);
    62                 scanf("%d", &v);
    63             }
    64         }
    65         for (int i = 1  ; i <= n ; i++)
    66             if (!dfn[i]) tarjan(i);
    67         for (int i = 1 ; i <= n ; i++) {
    68             for (int j = head[i] ; ~j ; j = edge[j].next) {
    69                 if (belong[edge[j].v] != belong[i]) {
    70                     in[belong[edge[j].v]]++;    //统计每个连通块的出度和入度
    71                     out[belong[i]]++;
    72                 }
    73             }
    74         }
    75         int sumin = 0, sumout = 0;
    76         for (int i = 1 ; i <= cnt ; i++) {    //遍历每个连通块
    77             if (!in[i]) sumin++;      //入度为0的连通分量个数
    78             if (!out[i])sumout++;     //出度为0的连通分量个数
    79         }
    80         printf("%d
    ", sumin);
    81         if (cnt == 1) printf("0
    ");   //如果该图已经是一个强连通图,只有一个强连通分量,则不需要加边
    82         else printf("%d
    ", max(sumin, sumout));       
    83     }
    84     return 0;
    85 }

    2018-09-30

  • 相关阅读:
    jquery ajax跨域取数据
    Python编写相关注意事项
    深入理解java.lang.String
    Java设计模式----迭代器模式
    Java设计模式----状态模式
    Java设计模式----观察者模式
    Java设计模式----适配器模式
    Java设计模式----外观模式
    Java设计模式----建造者模式
    Java设计模式----模板方法模式
  • 原文地址:https://www.cnblogs.com/00isok/p/9733817.html
Copyright © 2011-2022 走看看