POJ 1966 Cable TV Network (maximum flow)

$ POJ~1966~Cable~TV~Network $



$ solution: $

At first glance it may make it difficult to start, but this is directed at the network stream, so we bluntly. This question we have to let the connected graph is disconnected, it is bound to have two points to become none, this question of the range of data is small, so we try to enumerate violence two points. This becomes a minimum cut. But, ah? How to cut something is the point?

In order to close the knowledge we've learned, we would like to see a free, cut points can become cutting edge. Anyway, ever-changing network flow like most about the modeling. . . So we introduce a thing of the book:

  1. A node may be split into two nodes, an intermediate represented by the original node that edge
  2. One side can be split into two sides, the original edge represents the point intermediate
  3. Right side represents the middle of the point is whether the cut, right next to the edge is to exclude the influence inf (since it can not be cut off)

We use first and third property can solve this problem. Firstly, two $ I $ $ i + n $ and a node for each node. Then a value between the two nodes by a directed edge weights (from $ to $ i $ i + n $), if this edge is cut off in the minimum cut (equivalent to the original point is cut out). $ I $ node is then connected to the edges (weights positive infinity), $ i + n $ node Outgoing edges (weights positive infinity), positive infinity is even cut off to make only the middle side edge. Then we run it again maximum flow, which corresponds to the minimum cut on behalf of a point in each of the original, because the weight of 1, so the traffic is the answer.

Note: We have source and sink points are divided into two points, while the actual source network flow is $ S + n $, which even out side. Because of the nature of the source and sink points, these two points can not be cut off, so that they are not connected intermediate edge.



$ code: $

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>

#define ll long long
#define db double
#define rg register int

using namespace std;

int n,m,S,T;
int ans,top=1;
int dep[505];
int tou[505];
int qi[505];
int f[55][55];

struct su{
    int to,v,next;
}b[5005];

inline int qr(){
    register char ch; register bool sign=0; rg res=0;
    while(!isdigit(ch=getchar()))if(ch=='-')sign=1;
    while(isdigit(ch))res=res*10+(ch^48),ch=getchar();
    if(sign)return -res; else return res;
}

inline void add(int x,int y,int v){ //注意博主加边自带反向
    b[++top]=su{y,v,tou[x]}; tou[x]=top;
    b[++top]=su{x,0,tou[y]}; tou[y]=top;
}

inline bool bfs(int x){
    for(rg i=1;i<=x;++i)
        qi[i]=tou[i],dep[i]=0;
    queue<int> q; q.push(S); dep[S]=1;
    while(!q.empty()){
        rg i=q.front(); q.pop();
        for(rg j=tou[i];j;j=b[j].next)
            if(b[j].v&&!dep[b[j].to]){
                dep[b[j].to]=dep[i]+1;
                if(b[j].to==T)return 1;
                q.push(b[j].to);
            }
    } return 0;
}

inline int dfs(int i,int w){
    if(i==T||!w)return w;
    rg rest=w,f;
    for(rg &j=qi[i];j;j=b[j].next){
        if(b[j].v&&dep[b[j].to]==dep[i]+1){
            f=dfs(b[j].to,min(w,b[j].v));
            if(!f){dep[b[j].to]=-2; continue;}
            b[j].v-=f; b[j^1].v+=f; w-=f;
        } if(!w)break;
    }return rest-w;
}

inline void solve(){
    rg res=0; top=1;
    for(rg i=1;i<=n*2+2;++i) tou[i]=0; //初始化
    for(rg i=1;i<=n;++i){
        if(i!=S&&i!=T)add(i,i+n,1); //一点拆成两点,中间连边
        for(rg j=1;j<=n;++j)
            if(f[i][j])add(i+n,j,1e9); //连边注意是否有加n操作
    } S=S+n;
    while(bfs(n*2+2)) res+=dfs(S,1e9); //DInic
    ans=min(res,ans);
}

int main(){
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    rg t=qr();
    while(t--){
        n=qr();m=qr();
        for(rg i=1;i<=n;++i){
            for(rg j=i;j<=n;++j){
                f[i][j]=f[j][i]=0; //初始化
            }
        }
        for(rg i=1;i<=m;++i){
            rg x=qr()+1,y=qr()+1;
            f[x][y]=f[y][x]=1; //邻接矩阵读边
        }
        if(n==0||n==2){puts("0");continue;}
        if(m==0&&n&&n!=2){puts("1");continue;}//特判,这题有点卡细节
        ans=1e9;
        for(rg i=1;i<=n;++i){
            for(rg j=1;j<=n;++j){
                if(f[i][j]||i==j)continue; //注意两个相邻的点不可能通过割点不联通
                S=i;T=j; solve(); //枚举源汇点
            }
        } if(ans==1e9)ans=n; //无论怎么割点图都联通,就输出n
        printf("%d\n",ans);
    }
    return 0;
}

Guess you like

Origin www.cnblogs.com/812-xiao-wen/p/11257791.html