zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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
    ",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
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    20款最优秀的JavaScript编辑器
    清空windows系统网络配置
    如何禁止Chrome浏览器隐藏URL的WWW前缀
    EDK2开发环境搭建
    edk2中子目录介绍
    INTEL_BIOS 编译—for-ATOM_E3800
    英特尔vPro博锐技术激活
    gitea configure
    mpeg1、mpeg2和mpeg4标准对比分析和总结
    内置缓存
  • 原文地址:https://www.cnblogs.com/Narh/p/8621063.html
Copyright © 2011-2022 走看看