题解 【网络流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\n",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\n",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;
}

猜你喜欢

转载自www.cnblogs.com/zsq259/p/10510193.html