• [HNOI2012]矿场搭建


    题目传送门

    分析:

    这道题是跟$Tarjan$有关的一题。

    如果某一个点双连通分量中没有割顶,则这个点双的答案为$2$。因为塌了任何一个点,其他任意两点仍然连通。防止塌的点就是救援口,所以要设置$2$个。

    如果某一个点双连通分量中有一个割顶,说明至少有两个点双公用这一个割顶。所以必须保证每个点双中除割顶的其他任意一点是救援口,且只需一个。如果塌了割点,对每个点双无影响;如果塌了其中一个救援口,该点双能通过割点到达另一个点双的救援口。

    如果某一个点双连通分量中有两个或以上的割顶,则它不需要救援口。因为它如果塌了其中的一个割点,能通过另一个割点到达其他的救援口。

    最优性证明:以上方案中没有任何一个多余救援口,且能保证题意成立,且无法找到更优的方案。

    第二问方案数:将每个点双根据以上三种情况进行统计,累乘即可。

      1 #include <bits/stdc++.h>
      2 
      3 using namespace std;
      4 
      5 #define re register
      6 #define rep(i, a, b) for (re int i = a; i <= b; ++i)
      7 #define repd(i, a, b) for (re int i = a; i >= b; --i)
      8 #define maxx(a, b) a = max(a, b);
      9 #define minn(a, b) a = min(a, b);
     10 #define LL long long
     11 #define inf (1 << 30)
     12 
     13 const int maxn = 1000 + 10;
     14 
     15 struct Edge {
     16     int u, v, pre;
     17 };
     18 
     19 struct Graph {
     20     Edge edges[maxn << 1];
     21     int n, m, G[maxn];
     22     void init() {
     23         m = 0;
     24         memset(G, 0, sizeof(G));
     25     }
     26     void add(int u, int v) {
     27         edges[++m] = (Edge){u, v, G[u]};
     28         G[u] = m;
     29     }
     30     int dfs_clock, iscut[maxn], low[maxn], pre[maxn];
     31     stack<pair<int, int> > S;
     32     int bccno[maxn], bs, cnt[maxn];
     33     vector<int> bcc[maxn];
     34     void dfs(int u, int fa) {
     35         low[u] = pre[u] = ++dfs_clock;
     36         int child = 0;
     37         for (register int i = G[u]; i; i = edges[i].pre) {
     38             int v = edges[i].v;
     39             if (!pre[v]) {
     40                 S.push(make_pair(u, v));
     41                 child++;
     42                 dfs(v, u);
     43                 minn(low[u], low[v]);
     44                 if (low[v] >= pre[u]) {
     45                     iscut[u] = 1;
     46                     bcc[++bs].clear();
     47                     for (;;) {
     48                         pair<int, int> top = S.top(); S.pop();
     49                         if (bccno[top.first] != bs) bccno[top.first] = bs, bcc[bs].push_back(top.first);
     50                         if (bccno[top.second] != bs) bccno[top.second] = bs, bcc[bs].push_back(top.second);
     51                         if (top.first == u && top.second == v) break;
     52                     }
     53                 }
     54             }
     55             else if (v != fa) {
     56                 //S.push(make_pair(u, v));
     57                 minn(low[u], pre[v]);
     58             }
     59         }
     60         if (u == fa && child == 1) iscut[u] = 0;
     61     }
     62     pair<int, LL> tarjan() {
     63         memset(pre, 0, sizeof(pre));
     64         memset(low, 0, sizeof(low));
     65         memset(iscut, 0, sizeof(iscut));
     66         memset(bccno, 0, sizeof(bccno));
     67         bs = 0;
     68         rep(i, 1, n)
     69             if (!pre[i])
     70                 dfs(i, i);
     71         memset(cnt, 0, sizeof(cnt));
     72         rep(i, 1, bs)
     73             for (register int x = 0; x < bcc[i].size(); x++)
     74                 cnt[i] += iscut[bcc[i][x]] ? 1 : 0;
     75         LL ans = 1; int sum = 0;
     76         rep(i, 1, bs) {
     77             int tot = bcc[i].size();
     78             if (!cnt[i]) sum += 2, ans *= (tot-1)*tot/2;
     79             else if (cnt[i] == 1)
     80                 sum++, ans *= tot-1;
     81         }
     82         return make_pair(sum, ans);
     83     }
     84 } G;
     85 
     86 int n, T = 0;
     87 
     88 int main() {
     89     while (~scanf("%d", &n)) {
     90         T++;
     91         int N = 0;
     92         if (!n) break;
     93         G.init();
     94         rep(i, 1, n) {
     95             int u, v;
     96             scanf("%d%d", &u, &v);
     97             G.add(u, v);
     98             G.add(v, u);
     99             N = max(N, max(u, v));
    100         }
    101         G.n = N;
    102         pair<int, LL> ans = G.tarjan();
    103         printf("Case %d: %d %lld
    ", T, ans.first, ans.second);
    104     }
    105     return 0;
    106 }
  • 相关阅读:
    ES6/5比较
    Javascript中的var和let
    git中remotes/origin/HEAD指向的分支丢失
    js实用篇之数组、字符串常用方法
    JS设计模式一:单例模式
    Linux C 面试题总结 .
    深入理解javascript原型和闭包(15)——闭包
    一些有意思的面试题(持续更新) .C语言编程技巧札记
    一个三流大学生的北京三年 .
    C 字节对齐.我的算法学习之路
  • 原文地址:https://www.cnblogs.com/ac-evil/p/10348710.html
Copyright © 2020-2023  润新知