zoukankan      html  css  js  c++  java
  • 题解 【网络流24题】方格取数问题

    【网络流24题】方格取数问题

    Description

    在一个有m * n 个方格的棋盘中,每个方格中有一个正整数。现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大。试设计一个满足要求的取数算法。对于给定的方格棋盘,按照取数要求编程找出总和最大的数。

    Input

    第1 行有2 个正整数m和n,分别表示棋盘的行数和列数。
    接下来的m行,每行有n个正整数,表示棋盘方格中的数。

    Output

    将取数的最大总和输出

    Sample Input

    3 3
    1 2 3
    3 2 3
    2 3 1

    Sample Output

    11

    Hint

    数据范围:
    1<=N,M<=30

    Source

    网络流
    二分图点权最大独立集, 网络最小割

    解析

    这算是道网络流的入门题了。

    仔细想一下,

    如果一个点被选了,那么它周围的四个点一定不会选。

    反过来的话,我们可以选出不选的点,

    使剩下的点满足要求。

    因此,问题就转化成了使不选的点的权值和最小,

    所以,将图进行黑白染色,

    将一种颜色与源点连接,

    流量为点权,

    再连与它相邻的四个格子(边界有特判),流量为INF,

    然后另一种颜色就连汇点,流量也为它的点权。

    这样,源点和汇点就不能连通,

    因此,求出最小割,

    再用总点权减掉就行了。

    上AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    inline int read(){
        int sum=0,f=1;char ch=getchar();
        while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
        return f*sum;
    }
    
    const int INF=0x3f3f3f3f;
    struct node{
        int next,to,w;
    }e[100001];
    int m,n,s,t,sum=0;
    int a[10001],col[10001];
    int dx[4],v[10001],dis[10001];
    int head[10001],cnt=1;
    
    void add(int x,int y,int w){
        e[++cnt].to=head[x];
        e[cnt].next=y;
        e[cnt].w=w;
        head[x]=cnt;
    }
    
    void makecol(){
        queue <int> que;
        memset(col,0,sizeof(col));
        que.push(2);
        col[2]=1;
        while(!que.empty()){
            int x=que.front();
            que.pop();
            if(x%n!=2){
                int k=x-1;
                if(!col[k]) col[k]=3-col[x],que.push(k);
            }
            if(x%n!=1){
                int k=x+1;
                if(!col[k]) col[k]=3-col[x],que.push(k);
            }
            if(x>n+1){
                int k=x-n;
                if(!col[k]) col[k]=3-col[x],que.push(k);
            }
            if(x+n<=n*m+1){
                int k=x+n;
                if(!col[k]) col[k]=3-col[x],que.push(k);
            }
        }
    }
    
    void build(){
        for(int i=2;i<=n*m+1;i++){
            if(col[i]==1){
                add(i,t,a[i]);
                add(t,i,0);
            }
            else if(col[i]==2){
                add(s,i,a[i]);
                add(i,s,0);
                int x=i;
                if(x%n!=2){
                    int k=x-1;
                    add(x,k,INF);add(k,x,0);
                }
                if(x%n!=1){
                    int k=x+1;
                    add(x,k,INF);add(k,x,0);
                }
                if(x>n+1){
                    int k=x-n;
                    add(x,k,INF);add(k,x,0);
                }
                if(x+n<=n*m+1){
                    int k=x+n;
                    add(x,k,INF);add(k,x,0);
                }
            }
        }
    /*    for(int i=2;i<=cnt;i++){
            printf("to=%d next=%d w=%d
    ",e[i].to,e[i].next,e[i].w);
            }*/
    }
    
    bool bfs(){
        queue <int> q;
        memset(dis,0xff,sizeof(dis));
        q.push(s);
        dis[s]=0;
        while(!q.empty()){
            int x=q.front();
            q.pop();
            for(int i=head[x];i;i=e[i].to){
                int k=e[i].next;
                if(dis[k]>=0||!e[i].w) continue;
                dis[k]=dis[x]+1;
                q.push(k);
            }
        }
        if(dis[t]>0) return 1;
        return 0;
    }
    
    int dfs(int x,int mi){
        if(x==t) return mi;
        int ret;
        for(int i=head[x];i;i=e[i].to){
            int k=e[i].next;
            if(dis[k]-1!=dis[x]||!e[i].w) continue;
            if((ret=dfs(k,min(mi,e[i].w)))){
                e[i].w-=ret;
                e[i^1].w+=ret;
                return ret;
            }
        }
        return 0;
    }
    
    void DINIC(){
        int ans=0,ret;
        while(bfs()){
            while((ret=dfs(s,INF))){
                ans+=ret;
            }
        }
        printf("%d
    ",sum-ans);
        return ;
    }
    
    int main(){
        m=read();n=read();
        s=1;t=n*m+2;
        for(int i=2;i<=n*m+1;i++) a[i]=read(),sum+=a[i];
        dx[0]=1;dx[1]=-1;dx[2]=n;dx[3]=-n;
        makecol();
        build();
        DINIC();
        return 0;
    }
  • 相关阅读:
    450. K组翻转链表
    6. 合并排序数组 II
    64. 合并排序数组
    165. 合并两个排序链表
    103. 带环链表 II
    102. 带环链表
    [web安全原理]PHP命令执行漏洞基础
    [原题复现]-HITCON 2016 WEB《babytrick》[反序列化]
    《将博客搬至CSDN》
    PHP反序列化漏洞-CVE-2016-7124(绕过__wakeup)复现
  • 原文地址:https://www.cnblogs.com/zsq259/p/10510193.html
Copyright © 2011-2022 走看看