zoukankan      html  css  js  c++  java
  • [HNOI2012]矿场搭建

    LuoguP3225

    蒟蒻也是才开始看双联通分量,如果有不妥的地方还请巨佬们指出

    Code:

     1 #include <bits/stdc++.h>
     2 #define ll long long
     3 using namespace std;
     4 const int N = 1e4 + 7;
     5 int n, m;
     6 int tot, head[N];
     7 bool cut[N];//记录一个点是不是割点 
     8 vector<int> dcc[N];//记录每个点双里面点 
     9 int id, top, vdcc, dfn[N], low[N], stk[N];
    10 struct edge{
    11     int net, to;
    12 }e[N * 3];
    13 void add(int u, int v) {
    14     e[++tot] = {head[u], v};
    15     head[u] = tot;
    16 }
    17 void tarjan(int u, int fa) {//求点分模板 
    18     dfn[u] = low[u] = ++id;
    19     stk[++top] = u;
    20     if (u == fa && !head[u]) {//单独的点就计入单独的点分 
    21         dcc[++vdcc].push_back(u);
    22         return;
    23     }
    24     int flag = 0;
    25     for (int i = head[u]; i; i = e[i].net) {
    26         int to = e[i].to;
    27         if (!dfn[to]) {
    28             tarjan(to, u);
    29             low[u] = min(low[u], low[to]);
    30             if (low[to] >= dfn[u]) {
    31                 flag++;
    32                 if (u != fa || flag > 1) {
    33                     cut[u] = true;//记下割点 
    34                 }
    35                 vdcc++;
    36                 dcc[vdcc].clear();//多组数据要清空 
    37                 int y;
    38                 do {
    39                     y = stk[top--];
    40                     dcc[vdcc].push_back(y);
    41                 } while (y != to);//注意这里是to 
    42                 dcc[vdcc].push_back(u);
    43             }
    44         } else {
    45             low[u] = min(low[u], dfn[to]);
    46         }
    47     }
    48 }
    49 int main () {
    50     int Case = 0;
    51     while (scanf("%d", &m) && m != 0) {
    52         Case++;
    53         ll ans1 = 0, ans2 = 1; 
    54         vdcc = tot = top = id = 0;
    55         memset(head, 0, sizeof head);
    56         memset(cut, 0, sizeof cut);
    57         memset(dfn, 0, sizeof dfn);
    58         //注意一下多组数据的清空,low数组会被id更新,不用清 
    59         n = 0;
    60         for(int i = 1; i <= m; i++) {
    61             int u, v;
    62             scanf("%d%d", &u, &v);
    63             add(u, v), add(v, u);
    64             n = max(n, max(u, v));//题里面没说点标号就只好自己取max 
    65         }
    66         for (int i = 1; i <= n; i++) {
    67             if (!dfn[i]) {
    68                 tarjan(i, i);
    69             }
    70         }
    71         for (int i = 1; i <= vdcc; i++) {
    72             int cutnum = 0;
    73             int siz = (int)dcc[i].size();
    74             for (int j = 0; j < siz; j++) {
    75                 if (cut[dcc[i][j]]) {
    76                     cutnum++;//记录该点分之中的割点数 
    77                 }
    78             }
    79             if (siz == 1) {//单独的点特判一下 
    80                 ans1++;
    81                 continue;
    82             }
    83             if (cutnum == 1) {
    84                 ans1++;
    85                 ans2 *=(siz - 1);
    86                 //如果只有一个割点的话,必须要再建一个非割点的出口
    87                 //这样才能保证在割点坍塌之后该点分还能出去 
    88             } else if (!cutnum) {
    89                 ans1 += 2;
    90                 ans2 *= siz * (siz - 1) / 2;
    91                 //如果没有割点的话就必须建两个出口,然后就是C(n,2),化简后就是n*(n-1)/2
    92             }
    93             //还有一种情况就是有两个割点
    94             //此时无论哪个点塌了,该点分里的点都能有地方出去,所以不需要建出口了 
    95         }
    96         printf("Case %d: %lld %lld
    ", Case, ans1,ans2);
    97     }
    98     return 0;
    99 }
    View Code
  • 相关阅读:
    JAVA代码覆盖率工具JaCoCo-原理篇
    (转载)比较web ui 框架
    sql拼接
    解决com.mysql.jdbc.PacketTooBigException: Packet for query is too large问题
    字符串中重复出现字符串个数
    Unable to load annotation processor factory
    三目运算符
    WSGI剖析
    深入剖析cpp对象模型
    Cpp下匿名对象探究
  • 原文地址:https://www.cnblogs.com/Sundial/p/11830593.html
Copyright © 2011-2022 走看看