[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;
}
原文地址:https://www.cnblogs.com/NaVi-Awson/p/8584808.html