POJ 1966 Cable TV Network 【经典最小割问题】

Description

n个点的无向图,问最少删掉几个点,使得图不连通

n<=50 m也许可以到完全图?

Solution

最少,割点,不连通,可以想到最小割。

发现,图不连通,必然存在两个点不连通。

枚举源点汇点,要让源点汇点不连通。源点汇点不能割掉

网络建图:

为了割的是边,所以要点转化成边。

对于每个x,建立x‘=x+n,对于不是S、T的点(因为S、T不能割掉),x向x’连一条边权为1的边

对于原图的边e(x,y) x’->y 连接inf的边,y‘->x连接inf的边。

边权保证割的是点,不是边。

x‘->y连边保证,想走这条边,必须经过x。

源点汇点不唯一,所以要n^2枚举。

但是要保证S,T不直接相连,否则不可能分开。

(如果钦定0是源点,枚举汇点的话,可以hack掉

假设最优解必须割掉0,那么就ans大了

但是数据水)

然后每次重新建图。

跑dinic最小割,所有的最小割取min即可。

题目一些小坑:

1.图不连通?没关系,可以枚举得到最小割为0

2.m=0,同上

3.如果完全图?没有S、T满足不直接相邻,那么一定就是n

fl记录一下有没有dinic过即可。

4.n=1?同上fl可以判断。

Code

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
#define numb ch-‘0‘
using namespace std;
const int N=52;
const int inf=0x3f3f3f3f;
int n,m;
char ch;
void rd(int &x){
    x=0;
    while(!isdigit(ch=getchar()));
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
}
struct node{
    int nxt,to;
    int w;
}e[2*N*N+N];
int hd[2*N],cnt=1;
bool con[N][N];
void add(int x,int y,int z){
    e[++cnt].nxt=hd[x];
    e[cnt].to=y;
    e[cnt].w=z;
    hd[x]=cnt;
}

queue<int>q;
int d[2*N];
int s,t;

void pre(){
    memset(hd,0,sizeof hd);
    cnt=1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(j==i) continue;
            if(con[i][j]){

                add(i+n,j,inf/2);
                add(j,i+n,0);
            }
        }
        if(i!=s&&i!=t) add(i,i+n,1),add(i+n,i,0);
    }
}
bool bfs(){
    while(!q.empty())q.pop();
    memset(d,0,sizeof d);
    d[s+n]=1;
    q.push(s+n);
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(!d[y]&&e[i].w){
                d[y]=d[x]+1;
                q.push(y);
                if(y==t) return 1;
            }
        }
    }
    return 0;
}
int lp=0;
int dfs(int x,int flow){
    if(x==t) return flow;
    int rest=flow;
    for(int i=hd[x];i&&rest;i=e[i].nxt){
        int y=e[i].to;
        if(d[y]==d[x]+1&&e[i].w){
            int k=dfs(y,min(rest,e[i].w));
            if(!k) d[y]=0;
            rest-=k;
            e[i].w-=k;
            e[i^1].w+=k;
        }
    }
    return flow-rest;
}
int wrk(){
    pre();
    int ret=0;
    int flow;
    while(bfs()){
        while(flow=dfs(s+n,inf)) ret+=flow;
    }
    return ret;
}
int ans;
bool fl;
void clear(){
    memset(hd,0,sizeof hd);
    cnt=1;
    memset(con,0,sizeof con);
    ans=inf;
    fl=false;
}
int main()
{
    int x,y;
    while(scanf("%d",&n)!=EOF){
        clear();
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            rd(x);rd(y);
            x++;y++;
            con[x][y]=con[y][x]=1;
        }
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                if(con[i][j]) continue;
                fl=true;
                s=i,t=j;
                int tmp=wrk();
                ans=min(ans,tmp);
            }
        }
        if(!fl) ans=n;
        printf("%d\n",ans);
    }
    return 0;
}

这个题,体现了“点边转化”,“容量inf”的处理思想。

点边转化:把点的信息转移到边上,或者边信息转移到点上。

点变成边:拆点,两个点之间的边信息是点的信息。并且要保证,实际经过这个点,必须经过这个边。

    一般从上面的点x‘向下面y连边。

边变成点:把边拆成两个,中间加一个点,记录边的信息。

原文地址:https://www.cnblogs.com/Miracevin/p/9611007.html

时间: 2024-08-27 00:16:23

POJ 1966 Cable TV Network 【经典最小割问题】的相关文章

POJ 1966 Cable TV Network(无向图的顶点连通度)

POJ 1966 Cable TV Network 链接:http://poj.org/problem?id=1966 题意:有线电视网络中,中继器的连接是双向的.如果网络中任何两个中继器之间至少有一条路,则中继器网络称为是连通的,否则中继器网络是不连通的.一个空的网络.以及只有一个中继器的网络被认为是连通的.具有n 个中继器的网络的安全系数f 被定义成: (1) f 为n,如果不管删除多少个中继器,剩下的网络仍然是连通的: (2) f 为删除最少的顶点数,使得剩下的网络不连通. 现在给定一个有

POJ 1966 Cable TV Network(顶点连通度的求解)

Cable TV Network Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 4678   Accepted: 2163 Description The interconnection of the relays in a cable TV network is bi-directional. The network is connected if there is at least one interconnecti

POJ 1966 Cable TV Network

Cable TV Network Time Limit: 1000ms Memory Limit: 30000KB This problem will be judged on PKU. Original ID: 196664-bit integer IO format: %lld      Java class name: Main The interconnection of the relays in a cable TV network is bi-directional. The ne

UVA-1660 Cable TV Network (最小割)

题目大意:给一张n个点.m条边的无向图,求最小点割集的基数. 题目分析:求无向图最小点割集的基数可以变成求最小割.考虑单源s单汇t的无向图,如果要求一个最小点集,使得去掉这个点集后图不再连通(连通分量数目增多),只需将每个点拆成两个(入点和出点),并且之间连一条容量为1的弧,其他弧不变,在新网络上求最小割便得到这个最小点集的基数.但是本题无源无汇,可以指定一个点作为源点,枚举其它的点作为汇点,求得n-1个点集基数,取最小的便是答案.要注意每次枚举都要重新建图. 代码如下: # include<i

poj 1966 Cable TV Network 顶点连通度

题目链接 给一个图, n个点m条边, 求至少去掉多少个点可以使得图不再联通.随便指定一个点为源点, 枚举其他点为汇点的情况, 跑网络流, 求其中最小的情况. 如果最后ans为inf, 说明是一个完全图, 那么结果就为n. 1 #include <iostream> 2 #include <vector> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #inclu

POJ 1966:Cable TV Network(最小点割集)

http://poj.org/problem?id=1966 题意:给出一个由n个点,m条边组成的无向图.求最少去掉多少点才能使得图中存在两点,它们之间不连通. 思路:将点i拆成a和b,连一条a->b的容量为1的边,代表这个点只能走一次,然后如果点i和点j有边相连,那么将bi和aj相连,bj和ai相连,容量为INF,代表这条边可以走INF次. 然后O(n^2)枚举源点和汇点跑最大流,算的最小的最大流就是答案.(这个时候的最大流代表的是S跑到T需要经过多少路径(最小割),如果得到的最大流是INF,

poj1966Cable TV Network——无向图最小割(最大流)

题目:http://poj.org/problem?id=1966 把一个点拆成入点和出点,之间连一条边权为1的边,跑最大流即最小割: 原始的边权赋成inf防割: 枚举源点和汇点,直接相邻的两个点不必枚举: 注意:1.源点为枚举点i的出点,汇点为枚举点j的入点: 2.读入方式,免空格: 3.在dinic跑最大流的过程中,会改变边权,因此每次枚举都要复制一组边跑最大流,以免影响后面: 另:数据中的点从0开始,所以读入的时候++来使用. 代码如下: #include<iostream> #incl

ZOJ 2182 Cable TV Network(无向图点割-最大流)

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2182 题意:给出一个无向图,问最少删掉多少个顶点之后图变得不连通? 思路:将原图每个点拆点(i,i+n),连边<i,i+n,1>,对原图的边(u,v),连边<u+n,v,INF>,<v+n,u,INF>.然后对于每对顶点(i,j)跑最大流(i+n,j).所有最大流的最小值即为答案. struct node { int v,cap,nex

POJ 1637 Dual Core CPU 求最小割

据说这道题目是个很经典的题,好多人测最大流算法效率都是用的这题,只会dinic的弱菜第一法果断tle了,把vector改成数组了时候5s过. 下次什么时候学了isap在写一遍把 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostr