POJ1966 Cable TV Network

题目:http://poj.org/problem?id=1966

无向图中去掉最少的点使它不连通。

用网络流,割点就是把点变成边再割边。原边的容量为INF防割。

1.因为是无向图,所以拆点的时候应该拆成一个入点和一个出点,保证经过这点的话一定会经过拆出来的这条边。

 就可以把点的信息放在这条边上了。即容量为1表示“1个点”。

2.然后遍历起点和终点,更新答案。因为是无向图,所以 j = i + 1 即可。

 起点是该点的出点,终点是该点的入点。这样起点和终点都不会被删。于是遍历的时候如果是直接相连的两点就可以continue。

3.需要一些特判。如仅一个点也算连通等等。根据题目提示,只要当ans==INF(初值)的时候输出n就行了。

!重点:找一遍最大流后当前网络会变成残量网络,cap的值都改掉了!所以枚举下一组起点和终点之前要先复原cap!

!!重点:在dinic函数中 if(dfn[v=edge[i].to]==dfn[cr]+1&&edge[i].cap) 这一句中的&&edge[i].cap是不可或缺的!

     虽然我觉得在前面的bfs函数里 if(!dfn[v=edge[i].to]&&edge[i].cap) 就已经能限定edge[i].cap了,但去掉dinic里的判断真的会不对!具体为什么呢?

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int INF=250006;
int n,m,head[105],dfn[105],xnt,x,y;
int mxflow,cur[105],ans,s,t;
bool sid[105][105];
struct Edge{
    int next,to,cap,w;
    Edge(int n=0,int t=0,int c=0):next(n),to(t),cap(c),w(c) {}
}edge[5105];
queue<int> q;
int rd()
{
    char ch;
    int x=0;
    ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')
    {
        x=x*10+(int)ch-'0';
        ch=getchar();
    }
    return x;
}
void add(int x,int y,int k)
{
    edge[++xnt]=Edge(head[x],y,k);head[x]=xnt;
    edge[++xnt]=Edge(head[y],x,0),head[y]=xnt;
    sid[x][y]=1;sid[y][x]=1;
}
bool bfs()
{
    memset(dfn,0,sizeof dfn);
    while(q.size())q.pop();
    dfn[s]=1;q.push(s);
    while(q.size())
    {
        int k=q.front();q.pop();
        for(int i=head[k],v;i;i=edge[i].next)
            if(!dfn[v=edge[i].to]&&edge[i].cap)
            {
                dfn[v]=dfn[k]+1;q.push(v);
//                printf("    v=%d cap=%d\n",v,edge[i].cap);
                if(v==t)return dfn[t];
            }
    }
    return dfn[t];
}
int dinic(int cr,int flow)
{
    if(cr==t)return flow;
    int used=0;
    for(int& i=cur[cr],v;i;i=edge[i].next)
        if(dfn[v=edge[i].to]==dfn[cr]+1&&edge[i].cap)///////////!!!!!!!!!!
        {
//            printf("    flow=%d cap=%d\n",flow,edge[i].cap);
            int tmp=dinic(v,min(flow-used,edge[i].cap));
            if(!tmp)dfn[v]=0;
            used+=tmp;
            edge[i].cap-=tmp;
            edge[i^1].cap+=tmp;
//            printf("tmp=%d\n",tmp);
            if(used==flow)break;
        }
    return used;
}
int main()
{
    while(scanf("%d%d",&n,&m)==2)
    {
        xnt=1;ans=INF;
        memset(head,0,sizeof head);
        for(int i=0;i<n;i++)add(i,n+i,1);
        for(int i=1;i<=m;i++)
        {
            x=rd();y=rd();
            add(x+n,y,INF);add(y+n,x,INF);
        }
        for(int i=0;i<n;i++)
            for(t=i+1;t<n;t++)
            {
                if(sid[i+n][t])continue;
                s=i+n;
                mxflow=0;
                for(int i=2;i<=xnt;i++)edge[i].cap=edge[i].w;
                while(bfs())
                {
                    memcpy(cur,head,sizeof head);
                    mxflow+=dinic(s,INF);
                }
                ans=min(ans,mxflow);
//                printf("(%d)",ans);
            }
        if(ans==INF)ans=n;
        printf("%d\n",ans);
    }
    return 0;
}

 

posted on 2018-03-22 01:34  Narh  阅读(157)  评论(0编辑  收藏  举报

导航