POJ 1966 Cable TV Network

题目链接: POJ 1966 Cable TV Network

题目大意:

一张 \(N\) 个点的无向图,求最少删去多少点后可以使得图不连通。

\(0\leq N\leq 50\)

思路:

这里有一个小技巧:点转边

将每个点拆成一个出点和一个入点,入点连接所有进边,出点连接所有出边,两点间连一条权值为 \(1\) 的边,代表删除这个点的代价,而连在原先点与点之间的边权值设为 \(\infty\),防止删除了真正的边。

然后这题就转化成最小割了,枚举源点 \(S\) 和汇点 \(T\) ,将最小割更新答案即可。

细节:

挺板子的,就是 \(S\) 和 \(T\) 不能是同一个点即可, \(S\) 是该点的出点, \(T\) 是另外那个点的入点。

Code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<fstream>
#define mem(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,b,a) for(int i=b;i>=a;i--)
#define N 105
#define M 5200
#define Inf 0x3f3f3f3f
using namespace std;
inline int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
    return s*w;
}
int head[N],to[M],nxt[M];
int cnt,s,t;
int val[M],cap[M],d[N];
bool conn[N][N];
queue<int> q;
void init(){mem(head,-1),cnt=-1,mem(conn,false);}
void add_e(int a,int b,int w){
    nxt[++cnt]=head[a],head[a]=cnt,to[cnt]=b;
    val[cnt]=cap[cnt]=w;
    if(w)add_e(b,a,0);
}
bool bfs(){
    mem(d,0);
    while(!q.empty())q.pop();
    d[s]=1,q.push(s);
    while(!q.empty()){
        int cur=q.front(); q.pop();
        for(int i=head[cur];~i;i=nxt[i]){
            if(cap[i]&&!d[to[i]]){
                d[to[i]]=d[cur]+1;
                q.push(to[i]);
                if(to[i]==t)return true;
            }
        }
    }
    return false;
}
int dinic(int x,int flow){
    if(x==t)return flow;
    int rest=flow,k;
    for(int i=head[x];(~i)&&rest;i=nxt[i]){
        if(cap[i]&&d[to[i]]==d[x]+1){
            k=dinic(to[i],min(cap[i],rest));
            if(!k)d[to[i]]=0;
            cap[i]-=k,cap[i^1]+=k;
            rest-=k;
        }
    }
    return flow-rest;
}
int main(){
    int n,m,a,b;
    while(cin>>n>>m){
        if(n==1){
            cout<<"1\n";
            continue;
        }
        init();
        rep(i,1,m){
            a=read(),b=read(),conn[a][b]=true;
            add_e(a+n,b,Inf),add_e(b+n,a,Inf);
        }
        rep(i,0,n-1)add_e(i,i+n,1);
        int ans=n;
        rep(i,0,n-1)rep(j,0,n-1){
            if(conn[i][j]||i==j)continue;
            rep(k,0,cnt)cap[k]=val[k];
            s=i+n,t=j;
            int maxflow=0,flow;
            while(bfs()){
                while(flow=dinic(s,Inf))maxflow+=flow;
            }
            ans=min(ans,maxflow);
        }
        cout<<ans<<endl;
    }
    return 0;
}
上一篇:2021-04-02


下一篇:Android随机数