zoukankan      html  css  js  c++  java
  • 【HDU 1569 方格取数(2)】 网络流

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1569

    题目大意:给你一个m*n的格子的棋盘,每个格子里面有一个非负数。
                从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。

    解题思路:说实话,这样的网络流构图真的难想到,唉,练得太少了。

    定理: 最大点独立集=sum-最小点覆盖集。

             这里要我们求最大点独立集,由上面的定理我们就可以转换为求最小点覆盖集。我发现网上很多题解对于割这一块讲解的不知所云,可能是对割的理解还没深入吧,不会就看别人解题报告,然后自己按照自己的理解不知所云的讲。 这题可以用类似国际象棋黑白棋的方法解,每个点和它周围四个点连一条容量为无穷的边,源点和黑点(奇数点)相连,汇点和白点(偶数点)相连,剩下的就看你怎么割了,应该是这么割的:割掉最少最小的边,使得从源点的流量一点都不能到达汇点 ,等价于求源点到汇点的最大流。

            建好图直接上模板,此刻顿时变成渣渣题了。

    View Code
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    
    const int mn=3333;
    const int mm=1000000;
    const int oo=0x3fffffff;
    int node, st, sd, edge;
    int flow[mm], reach[mm], next[mm];
    int head[mn], work[mn], dis[mn], que[mn];
    
    void init(int node_, int st_, int sd_)
    {
        node=node_, st=st_, sd=sd_;
        for(int i=0; i<node; i++) head[i]=-1;
        edge=0;
    }
    
    void addedge(int u, int v, int c1, int c2)
    {
        reach[edge]=v, flow[edge]=c1,  next[edge]=head[u], head[u]=edge++;
        reach[edge]=u, flow[edge]=c2,  next[edge]=head[v], head[v]=edge++;
    }
    
    bool bfs()
    {
        int u, v, l=0, h=0;
        for(int i=0; i<node; i++) dis[i]=-1;
        que[l++]=st;
        dis[st]=0;
        while(l!=h)
        {
            u=que[h++];
            if(h==mn) h=0;
            for(int i=head[u]; i>=0; i=next[i])
            {
                v=reach[i];
                if(flow[i]&&dis[v]<0)
                {
                    dis[v]=dis[u]+1;
                    que[l++]=v;
                    if(l==mn) l=0;
                    if(v==sd) return true;
                }
            }
        }
        return false;
    }
    
    int dfs(int u, int exp)
    {
        if(u==sd) return exp;
        for(int &i=work[u]; i>=0; i=next[i])
        {
            int v=reach[i], tp;
            if(flow[i]&&dis[v]==dis[u]+1&&(tp=dfs(v,min(flow[i],exp))>0))
            {
                flow[i]-=tp;
                flow[i^1]+=tp;
                return tp;
            }
        }
        return 0;
    }
    
    int Dinic()
    {
        int max_flow=0, flow;
        while(bfs())
        {
            for(int i=0; i<node; i++) work[i]=head[i];
            while(flow=dfs(st,oo)) max_flow+=flow;
        }
        return max_flow;
    }
    
    int main()
    {
        int m;
        while(cin >> m)
        {
            init(m*m+2,0,m*m+1);
            int sum=0, val;
            for(int i=1; i<=m; i++)
                for(int j=1; j<=m; j++)
                {
                   scanf("%d",&val);
                   sum+=val;
                   if((i+j)&1)
                   {
                       addedge(st,(i-1)*m+j,val,0);
                       if(i!=1) addedge((i-1)*m+j,(i-2)*m+j,oo,0);
                       if(i!=m) addedge((i-1)*m+j,i*m+j,oo,0);
                       if(j!=1) addedge((i-1)*m+j,(i-1)*m+j-1,oo,0);
                       if(j!=m) addedge((i-1)*m+j,(i-1)*m+j+1,oo,0);
                   }
                   else addedge((i-1)*m+j,sd,val,0);
                }
            printf("%d\n",sum-Dinic());
        }
        return 0;
    }


  • 相关阅读:
    ubuntu 安装mysql和redis 开放远程连接
    linux时间不对,执行ntpdate时间同步始终不对。
    Web漏洞
    生产者消费者模型
    多进程抢票问题
    socket通讯-----UDP
    python3读写csv文件
    # 把csv转xls
    python os模块 用资源管理器显示文件,pyinstall打包命令
    创建一个最简单的pyqt5窗口
  • 原文地址:https://www.cnblogs.com/kane0526/p/2981087.html
Copyright © 2011-2022 走看看