381. 有线电视网络

题目链接

381. 有线电视网络

给定一张 \(n\) 个点 \(m\) 条边的无向图,求最少去掉多少个点,可以使图不连通。

如果不管去掉多少个点,都无法使原图不连通,则直接返回 \(n\)

输入格式

输入包含多组测试数据。

每组数据占一行,首先包含两个整数 \(n\)\(m\),接下来包含 \(m\) 对形如 \((x,y)\) 的数对,形容点 \(x\) 与点 \(y\) 之间有一条边。

数对 \((x,y)\) 中间不会包含空格,其余地方用一个空格隔开。

输出格式

每组数据输出一个结果,每个结果占一行。

数据范围

\(0 \le n \le 50\)

输入样例:

0 0
1 0
3 3 (0,1) (0,2) (1,2)
2 0
5 7 (0,1) (0,2) (1,3) (1,2) (1,4) (2,3) (3,4)

输出样例:

0
1
3
0
2

解题思路

最小割

建图:因为如果不连通的话最后必定有两点不连通,不妨将这两个点作为源点和汇点,即枚举源点 \(s\) 和汇点 \(t\),如果是要删除边使图不连通,则很显然删除割边即可,即最小割即为答案,但这里要求删除点,不妨考虑拆点,将所有点拆分为入点和出点,在流网络中入点向出点连一条容量为 \(1\) 的边,其他边容量足够大,由最小割要求的是最小的割,或者最大流最小割定理,由于跑最大流是一定要经过点,而点的容量是有限的,即最大流一定是有限的,即最小割有限,最后的割边就相当于是点。另外还有一个优化:不用枚举源点或汇点,即将其中一个固定,\(\color{red}{为什么?}\)由于固定的点一定在 \(S\) 或者 \(T\) 中,假设在 \(S\) 中,则由于是无向图,即对应流网络中除去入点和出点之间的边其余正边和反边的容量都是足够大,将 \(s\) 和固定点交换得到的结果还是一样的(不妨想象成所有的流量逆行)

  • 时间复杂度:\(O(n^5)\)

代码

// Problem: 有线电视网络
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/383/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=105,M=(55+2500)*2,inf=1e9;
int n,m,S,T;
int h[N],f[M],ne[M],e[M],idx;
int d[N],hh,tt,q[N],cur[N];
void add(int a,int b,int c)
{
	e[idx]=b,f[idx]=c,ne[idx]=h[a],h[a]=idx++;
	e[idx]=a,f[idx]=0,ne[idx]=h[b],h[b]=idx++;
}
bool bfs()
{
    memset(d,-1,sizeof d);
    d[S]=hh=tt=0;
    q[0]=S;
    cur[S]=h[S];
    while(hh<=tt)
    {
        int x=q[hh++];
        for(int i=h[x];~i;i=ne[i])
        {
            int y=e[i];
            if(d[y]==-1&&f[i])
            {
                d[y]=d[x]+1;
                cur[y]=h[y];
                if(y==T)return true;
                q[++tt]=y;
            }
        }
    }
    return false;
}
int dfs(int x,int limit)
{
    if(x==T)return limit;
    int flow=0;
    for(int i=cur[x];~i&&flow<limit;i=ne[i])
    {
        cur[x]=i;
        int y=e[i];
        if(d[y]==d[x]+1&&f[i])
        {
            int t=dfs(y,min(f[i],limit-flow));
            if(!t)d[y]=-1;
            f[i]-=t,f[i^1]+=t,flow+=t;
        }
    }
    return flow;
}
int dinic()
{
    int res=0,flow;
    while(bfs())while(flow=dfs(S,inf))res+=flow;
    return res;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
    	memset(h,-1,sizeof h);
    	idx=0;
    	for(int i=1;i<=n;i++)add(i,i+n,1);
    	for(int i=1;i<=m;i++)
    	{
    		int x,y;
    		scanf(" (%d,%d)",&x,&y);
    		x++,y++;
    		add(x+n,y,inf),add(y+n,x,inf);
    	}
    	int res=n;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<i;j++)
    		{
    			S=i+n,T=j;
    			for(int i=0;i<idx;i+=2)f[i]+=f[i^1],f[i^1]=0;
    			res=min(res,dinic());
    		}
    	printf("%d\n",res);
    }
    return 0;
}
posted @ 2022-12-01 09:58  zyy2001  阅读(63)  评论(0编辑  收藏  举报