• BZOJ2730 [HNOI2012]矿场搭建


    Solution

    输入中没有出现过的矿场点是不用考虑的, 所以不用考虑只有 一个点 的点双联通分量。

    要使某个挖矿点倒塌, 相当于割去这个点, 所以我们求一遍割点和点双联通分量。

    之后的点双联通分量构成一棵树。 树上的节点有两种情况

     

    1: 仅有一条边(仅有 一个割点 在内部)—— 相当与叶子节点, 把它与父亲节点相连的割点割去后,必须在里面设一个逃生出口

    2: 大于一条边(有大于一个割点在内部 )——割去其中一个割点时, 还可以通过另一个割点到达逃生出口, 所以不用设置。

     

    所以我们要求的就是在所有 仅含一个割点的 点双联通分量 内设置 一个 逃生出口, 并根据 乘法原理 计算方案数。

    特别的: 当整个图是一个 点双连通图时, 设置任意 两个 逃生出口即可。

    Code

     1 #include<cstdio>
     2 #include<vector>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define rd read()
     6 #define R register
     7 #define ll long long
     8 using namespace std;
     9 
    10 const int N = 1e3;
    11 
    12 int head[N], tot;
    13 int dfn[N], low[N], col_num;//col_num为点双联通分量个数
    14 int n, m, mark[N], cut[N], rt, maxn, cut_num[N];//cut_num为点双联通分量内的割点数
    15 int st[N], tp, cnt;
    16 ll ans1, ans2;
    17 
    18 vector<int> q[N];
    19 struct edge {
    20     int nxt, to, fr;
    21 }e[N << 3];
    22 
    23 int read() {
    24     int X = 0, p = 1; char c = getchar();
    25     for(; c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1;
    26     for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0';
    27     return X * p;
    28 }
    29 
    30 void add(int u, int v) {
    31     e[++tot].to = v;
    32     e[tot].nxt = head[u];
    33     e[tot].fr = u;
    34     head[u] = tot;
    35 }
    36 
    37 void tarjan(int u) {
    38     dfn[u] = low[u] = ++cnt;
    39     st[++tp] = u;
    40     int flag = 0;
    41     for(R int i = head[u]; i; i = e[i].nxt) {
    42         R int nt = e[i].to;
    43         if(!dfn[nt]) {
    44             tarjan(nt);
    45             low[u] = min(low[u], low[nt]);
    46             if(low[nt] >= dfn[u]) {
    47                 col_num++;
    48                 flag ++;
    49                 if(flag > 1 || u != rt)
    50                     cut[u] = 1;
    51                 for(; tp;) {
    52                     int z = st[tp--];
    53                     q[col_num].push_back(z);
    54                     if(z == nt) break;
    55                 }
    56                 q[col_num].push_back(u);
    57             }
    58         } else low[u] = min(low[u], dfn[nt]);
    59     }
    60 }
    61 
    62 void init() {
    63     for(int i = 1; i <= col_num; ++i)
    64         q[i].clear();
    65     ans1 = maxn = col_num = cnt = tot = 0;
    66     ans2 = 1;
    67     memset(dfn, 0, sizeof(dfn));
    68     memset(mark, 0, sizeof(mark));
    69     memset(cut, 0, sizeof(cut));
    70     memset(low, 0, sizeof(low));
    71     memset(head, 0, sizeof(head));
    72     memset(cut_num, 0, sizeof(cut_num));
    73 }
    74 
    75 int main()
    76 {
    77     for(int T = 1; ; T++) {
    78         n = rd;
    79         if(!n) return 0;
    80         init();
    81         for(int i = 1; i <= n; ++i) {
    82             int u = rd, v = rd;
    83             add(u, v); add(v, u);
    84             mark[u] = mark[v] = 1;
    85             maxn = max(maxn, u);
    86             maxn = max(maxn, v);
    87         }
    88         for(int i = 1; i <= maxn; ++i)
    89             if(!dfn[i] && mark[i]) tarjan(rt = i);
    90         for(int i = 1; i <= col_num; ++i)
    91             for(int j = 0, len = q[i].size(); j < len; ++j) {
    92                 if(cut[q[i][j]]) cut_num[i]++;
    93             }
    94         for(int i = 1; i <= col_num; ++i)
    95                 if(cut_num[i] == 1) ans1++, ans2 = ans2 * (int)(q[i].size() - 1);
    96         printf("Case %d: %lld %lld
    ", T, ans1 ? ans1 : 2, ans1 ? ans2 : (int)(q[1].size() - 1) * q[1].size()/ 2);
    97     }
    98 }
    View Code
  • 相关阅读:
    那些年搞不懂的多线程、同步异步及阻塞和非阻塞(一)---多线程简介
    java中IO流详细解释
    Java IO流学习总结
    MySQL数据库中索引的数据结构是什么?(B树和B+树的区别)
    使用Redis存储Nginx+Tomcat负载均衡集群的Session
    Redis 3.2.4集群搭建
    JDK1.8源码分析之HashMap
    java HashMap和LinkedHashMap区别
    Java中原子类的实现
    多线程-传统定时任务
  • 原文地址:https://www.cnblogs.com/cychester/p/9634752.html
Copyright © 2020-2023  润新知