• [HNOI 2012]矿场搭建


    Description

    题库链接

    给你一个 (n) 条边的无向图。让你在图中标记一些关键点,使得去掉图中任意一个点后,其余的所有点都能与至少一个关键点联通。问最少标点数以及点最少的前提下的方案数。

    (1leq nleq 500)

    Solution

    显然的结论就是找到所有点双后。讨论每个点双含有多少个割点即可。若没有割点那么这个点双要放两个关键点;若有一个割点,则只需放一个即可;若两个割点,则不需要放。

    缩完割点后直接讨论即可。

    Code

    //It is made by Awson on 2018.3.16
    #include <bits/stdc++.h>
    #define LL long long
    #define dob complex<double>
    #define Abs(a) ((a) < 0 ? (-(a)) : (a))
    #define Max(a, b) ((a) > (b) ? (a) : (b))
    #define Min(a, b) ((a) < (b) ? (a) : (b))
    #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
    #define writeln(x) (write(x), putchar('
    '))
    #define lowbit(x) ((x)&(-(x)))
    using namespace std;
    const int N = 500;
    void read(int &x) {
        char ch; bool flag = 0;
        for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
        for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
        x *= 1-2*flag;
    }
    void print(int x) {if (x > 9) print(x/10); putchar(x%10+48); }
    void write(int x) {if (x < 0) putchar('-'); print(Abs(x)); }
    
    int m, u, v;
    struct tt {int to, next; }edge[(N<<1)+5];
    struct Edge {int u, v; };
    int path[N+5], top;
    int dfn[N+5], low[N+5], vis[N+5], cut[N+5], bccno[N+5], bccnum, times, cnt;
    stack<Edge>S;
    vector<int>bcc[N+5];
    
    void dfs(int u, int fa) {
        dfn[u] = low[u] = ++times; int ch = 0;
        for (int i = path[u]; i; i = edge[i].next) {
        int v = edge[i].to; Edge e = (Edge){u, v};
        if (dfn[v] == 0) {
            S.push(e); ++ch;
            dfs(v, u); low[u] = Min(low[u], low[v]);
            if (low[v] >= dfn[u]) {
            cut[u] = 1; bcc[++cnt].clear();
            while (true) {
                Edge w = S.top(); S.pop();
                if (bccno[w.u] != cnt) bccno[w.u] = cnt, bcc[cnt].push_back(w.u);
                if (bccno[w.v] != cnt) bccno[w.v] = cnt, bcc[cnt].push_back(w.v);
                if (w.u == u && w.v == v) break;
            }
            }
        }else if (v != fa) low[u] = Min(low[u], dfn[v]);
        }
        if (fa == 0 && ch == 1) cut[u] = 0;
    }
    void add(int u, int v) {edge[++top].to = v, edge[top].next = path[u], path[u] = top; }
    void work() {
        memset(path, top = 0, sizeof(path)), memset(dfn, times = 0, sizeof(dfn));
        memset(cut, cnt = 0, sizeof(cut)), memset(vis, 0, sizeof(vis));
        memset(bccno, bccnum = 0, sizeof(bccno));
        for (int i = 1; i <= m; i++) read(u), read(v), vis[u] = vis[v] = 1, add(u, v), add(v, u);
        for (int i = 1; i <= N; i++) if (!dfn[i] && vis[i]) dfs(i, 0);
        int ans1 = 0; unsigned LL ans2 = 1;
        for (int i = 1; i <= cnt; i++) {
        int sz = bcc[i].size(), t = 0;
        for (int j = 0; j < sz; j++) if (cut[bcc[i][j]]) ++t;
        sz -= t;
        if (t == 0) ans1 += 2, ans2 *= 1LL*sz*(sz-1)/2;
        else if (t == 1) ans1++, ans2 *= sz;
        }
        printf("%d %lld
    ", ans1, ans2);
    }
    int main() {
        int t = 0;
        while (~scanf("%d", &m) && m != 0)
        ++t, printf("Case %d: ", t), work();
        return 0;
    }
  • 相关阅读:
    Python环境搭建
    appium的android端的环境搭建(Window)
    Unittest中常用的十四种断言方法
    Leetcode-141(判断链表是否存在环)
    Leetcode-88(归并两个有序数组)
    Leetcode-680(回文字符串)
    Leetcode-345(反转字符串中的元音字符)
    Leetcode-633 (两数平方和)
    Leetcode-167(有序数组的 Two Sum)
    判断是否为小数
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8584808.html
Copyright © 2020-2023  润新知