SP300 CABLETV - Cable TV Network题解

裁剪自我的blog

题意:给出一个图,问最少删多少个点使得图不连通。

考虑转换为 0. 0. 0.

我们可以想到拆点:

在这里插入图片描述

把原图中点 i i i 去掉就先当于,在新图中把 i → i ′ i \rightarrow i' ii 删掉了,这样 i ⇝ j i \rightsquigarrow j ij 的路径就不复存在了。

我们用 0. 0. 0. 的套路,枚举 u , v u, v u,v 不连通。

构造好了,我们来看看怎么从原图转化到新构造的图,就是不存在 u ′ ⇝ v u' \rightsquigarrow v uv

理解:

如图,例如 u ⇝ v u \rightsquigarrow v uv 的路

在这里插入图片描述
路径为
在这里插入图片描述

相当于我们要阻塞这条增广路,但是我们发现如果这样增广的话,会将 u , v u, v u,v 两点删去(原图),所以我们选择 u ′ , v u', v u,v

但是还有一种情况,它饶了一圈然后删掉了 u → u ′ u \rightarrow u' uu, v → v ′ v \rightarrow v' vv 呢?,这个时候这个路径上一定存在一条非 u → u ′ u \rightarrow u' uu, v → v ′ v \rightarrow v' vv 的路径,那么我们选择删去这条边而不选择 u → u ′ u \rightarrow u' uu 就行了(当然我们实际打代码时不需要管这条增广路到底删去了哪条边,只要知道它一定能构造出来就行了)。

除了这种情况没有非 u → u ′ u \rightarrow u' uu, v → v ′ v \rightarrow v' vv 的路径 (即有 u ′ → v u' \rightarrow v uv

在这里插入图片描述

这个时候增广路为 + ∞ +\infty +,我们就可以不用特判了。

所以其实最后代码非常简单,但是思维难度还是挺大的。(逻辑链条短,但是思维很非人……)

#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstdlib> 
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define fi first
#define se second
#define db double
#define LL long long
#define ULL unsigned long long
#define PII pair <int, int>
#define MP(x,y) make_pair (x, y)
#define rep(i,j,k) for (int i = (j); i <= (k); ++i)
#define per(i,j,k) for (int i = (j); i >= (k); --i)

template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return x > 0 ? x : -x; }
template <typename T>
void read (T &x) {
	x = 0; T f = 1;
	char ch = getchar ();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar ();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + ch - '0';
		ch = getchar ();
	}
	x *= f;
}
template <typename T, typename... Args>
void read (T &x, Args&... args) {
	read (x); read (args...);
}
char For_Print[25];
template <typename T>
void write (T x) {
	if (x == 0) { putchar ('0'); return; }
	if (x < 0) { putchar ('-'); x = -x; }
	int poi = 0;
	while (x) {
		For_Print[++poi] = x % 10 + '0';
		x /= 10;
	}
	while (poi) putchar (For_Print[poi--]);
}
template <typename T>
void print (T x, char ch) {
	write (x); putchar (ch);
}

const LL Mod = 1e9 + 7;
const int Maxn = 2 * 1e3;
const int Maxm = 1e5;
const LL Inf = 0x3f3f3f3f;

void del (LL &x, LL y) { ((x -= y) < 0) && (x += Mod); }
void add (LL &x, LL y) { ((x += y) >= Mod) && (x -= Mod); }

struct edge {
    int to[Maxm * 2 + 5], Next[Maxm * 2 + 5]; LL val[Maxm * 2 + 5];
    int len, Head[Maxn + 5];
    edge () { len = 1; memset (Head, 0, sizeof Head); }
    void Init () {
        len = 1;
        memset (Head, 0, sizeof Head);
    }
    void plus (int x, int y, LL w) {
        to[++len] = y;
        Next[len] = Head[x];
        val[len] = w;
        Head[x] = len;
    }
    void add (int x, int y, LL w) {
    	plus (x, y, w); plus (y, x, 0);
	}
}mp;

int s, t;
int hh, tt, q[Maxn + 5];
int depth[Maxn + 5], cur[Maxn + 5];
bool BFS () {
	rep (i, 1, tt) depth[q[i]] = 0;
    hh = 1; tt = 0; q[++tt] = s;
	depth[s] = 1; cur[s] = mp.Head[s];
    while (hh <= tt) {
        int u = q[hh++];
        for (int i = mp.Head[u]; i; i = mp.Next[i]) {
            int v = mp.to[i]; LL w = mp.val[i];
            if (w == 0) continue;
            if (depth[v]) continue;
            depth[v] = depth[u] + 1;
            cur[v] = mp.Head[v];
            q[++tt] = v;
            if (v == t) return 1;
        }
    }
    return 0;
}
LL DFS (int u, LL Up) {
    if (u == t) return Up;
    if (Up == 0) return 0;
    LL flow = 0;
    for (int i = cur[u]; i && Up != flow; i = mp.Next[i]) {
        int v = mp.to[i]; LL w = mp.val[i];
        cur[u] = i;
        if (w == 0) continue;
        if (depth[v] != depth[u] + 1) continue;
        LL tmp = DFS (v, Min (Up - flow, w));
        if (tmp == 0) depth[v] = -1;
        flow += tmp; mp.val[i] -= tmp; mp.val[i ^ 1] += tmp;
    }
    return flow;
}
LL Dinic () {
	LL flow = 0;
	while (BFS ()) {
		flow += DFS (s, Inf);
	}
	return flow;
}

int n, m;
int x[Maxn + 5], y[Maxn + 5];

int main () {
	// freopen ("D:\\lihan\\1.in", "r", stdin);
	// freopen ("D:\\lihan\\1.out", "w", stdout);

    while (cin >> n >> m) {
        rep (i, 1, m) read (x[i], y[i]), x[i]++, y[i]++;

        LL ans = n;
        rep (date_t, 2, n) {
            mp.Init ();

            s = 1 + n; t = date_t;

            rep (i, 1, n) mp.add (i, i + n, 1);
            rep (i, 1, m) {
                mp.add (x[i] + n, y[i], 1);
                mp.add (y[i] + n, x[i], 1);
            }
            ans = Min (ans, Dinic ());
        }
        if (ans == n - 1) {
            print (n, '\n');
        }
        else {
            print (ans, '\n');
        }
    }
	return 0;
}

posted @ 2021-12-09 13:56  C2022lihan  阅读(36)  评论(0编辑  收藏  举报