zoukankan      html  css  js  c++  java
  • 734. [网络流24题] 方格取数问题 二分图点权最大独立集/最小割/最大流

    «问题描述:
    在一个有m*n 个方格的棋盘中,每个方格中有一个正整数。现要从方格中取数,使任
    意2 个数所在方格没有公共边,且取出的数的总和最大。试设计一个满足要求的取数算法。
    «编程任务:
    对于给定的方格棋盘,按照取数要求编程找出总和最大的数。
    «数据输入:
    由文件grid.in提供输入数据。文件第1 行有2 个正整数m和n,分别表示棋盘的行数
    和列数。接下来的m行,每行有n个正整数,表示棋盘方格中的数。

    【问题分析】

    二分图点权最大独立集,转化为最小割模型,从而用最大流解决。

    【建模方法】

    首先把棋盘黑白染色,使相邻格子颜色不同,所有黑色格子看做二分图X集合中顶点,白色格子看做Y集合顶点,建立附加源S汇T。

    1、从S向X集合中每个顶点连接一条容量为格子中数值的有向边。
    2、从Y集合中每个顶点向T连接一条容量为格子中数值的有向边。
    3、相邻黑白格子Xi,Yj之间从Xi向Yj连接一条容量为无穷大的有向边。

    求出网络最大流,要求的结果就是所有格子中数值之和减去最大流量。

    【建模分析】

    这是一个二分图最大点权独立集问题,就是找出图中一些点,使得这些点之间没有边相连,这些点的权值之和最大。独立集与覆盖集是互补的,求最大点权独立集可以转化为求最小点权覆盖集(最小点权支配集)。最小点权覆盖集问题可以转化为最小割问题解决。结论:最大点权独立集 = 所有点权 - 最小点权覆盖集 = 所有点权 - 最小割集 = 所有点权 - 网络最大流。

    对于一个网络,除去冗余点(不存在一条ST路径经过的点),每个顶点都在一个从S到T的路径上。割的性质就是不存在从S到T的路径,简单割可以认为割边关联的非ST节点为割点,而在二分图网络流模型中每个点必关联到一个割点(否则一定还有增广路,当前割不成立),所以一个割集对应了一个覆盖集(支配集)。最小点权覆盖集就是最小简单割,求最小简单割的建模方法就是把XY集合之间的变容量设为无穷大,此时的最小割就是最小简单割了。

    /* 
     * Problem: 线性规划与网络流24题 #9 方格取数问题
     * Author: Guo Jiabao
     * Time: 2009.6.27 19:06
     * State: Solved
     * Memo: 网络最大流 二分图点权最大独立集
    */
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    using namespace std;
    const int MAXL=50,MAXN=50*50,MAXM=MAXN*8,INF=~0U>>1;
    const int dx[]={0,0,-1,1},dy[]={-1,1,0,0};
    struct edge
    {
        edge *next,*op;
        int t,c;
    }*V[MAXN],*P[MAXN],ES[MAXM],*Stae[MAXN];
    int N,M,S,T,C,EC,Ans,Maxflow,Total;
    int Lv[MAXN],Stap[MAXN],Map[MAXL][MAXL];
    inline void addedge(int a,int b,int c)
    {
        ES[++EC].next = V[a]; V[a]=ES+EC; V[a]->t=b; V[a]->c=c;
        ES[++EC].next = V[b]; V[b]=ES+EC; V[b]->t=a; V[b]->c=0;
        V[a]->op = V[b]; V[b]->op = V[a];
    }
    void init()
    {
        int i,j,k,c;
        freopen("grid.in","r",stdin);
        freopen("grid.out","w",stdout);
        scanf("%d%d",&M,&N);
        S=0; T=N*M+1;
        for (i=1;i<=M;i++)
        {
            for (j=1;j<=N;j++)
            {
                scanf("%d",&c);
                Total += c;
                Map[i][j] = ++C;
                if ((i+j)%2==0)
                    addedge(S,C,c);
                else
                    addedge(C,T,c);
            }
        }
        for (i=1;i<=M;i++)
        {
            for (j=1;j<=N;j++)
            {
                if ((i+j)%2==0)
                {
                    for (k=0;k<4;k++)
                    {
                        int x=i+dx[k],y=j+dy[k];
                        if (x>=1 && x<=M && y>=1 && y<=N)
                            addedge(Map[i][j],Map[x][y],INF);
                    }
                }
            }
        }
    }
    bool Dinic_Label()
    {
        int head,tail,i,j;
        Stap[head=tail=0]=S;
        memset(Lv,-1,sizeof(Lv));
        Lv[S]=0;
        while (head<=tail)
        {
            i=Stap[head++];
            for (edge *e=V[i];e;e=e->next)
            {
                j=e->t;
                if (e->c && Lv[j]==-1)
                {
                    Lv[j] = Lv[i]+1;
                    if (j==T)
                        return true;
                    Stap[++tail] = j;
                }
            }
        }
        return false;
    }
    void Dinic_Augment()
    {
        int i,j,delta,Stop;
        for (i=S;i<=T;i++)
            P[i] = V[i];
        Stap[Stop=1]=S;
        while (Stop)
        {
            i=Stap[Stop];
            if (i!=T)
            {
                for (;P[i];P[i]=P[i]->next)
                    if (P[i]->c && Lv[i] + 1 == Lv[j=P[i]->t])
                        break;
                if (P[i])
                {
                    Stap[++Stop] = j;
                    Stae[Stop] = P[i];
                }
                else
                    Stop--,Lv[i]=-1;
            }
            else
            {
                delta = INF;
                for (i=Stop;i>=2;i--)
                    if (Stae[i]->c < delta)
                        delta = Stae[i]->c;
                Maxflow += delta;
                for (i=Stop;i>=2;i--)
                {
                    Stae[i]->c -= delta;
                    Stae[i]->op->c += delta;
                    if (Stae[i]->c==0)
                        Stop = i-1;
                }
            }
        }
    }
    void Dinic()
    {
        while (Dinic_Label())
            Dinic_Augment();
    }
    int main()
    {
        init();
        Dinic();
        Ans = Total - Maxflow;
        printf("%d
    ",Ans);
        return 0;
    }
  • 相关阅读:
    Python连接redis时要注意的点
    Python SQLAlchemy多对多外键关联时表结构
    SQLAlchemy中解决数据库访问时出现的Incorrect string value: xxx at row 484
    HDFS集群数据不均衡处理
    elasticsearch数据过期删除处理
    docker使用技巧小记
    kubeadm部署kubernetes-1.12.0 HA集群-ipvs
    k8s全栈监控之metrics-server和prometheus
    k8s小工具
    k8s集群之上游dns--dnsmasq,统一管理kubernetes的dns解析
  • 原文地址:https://www.cnblogs.com/Aragaki/p/7554744.html
Copyright © 2011-2022 走看看