1907 方格取数 3

1907 方格取数 3

 

 时间限制: 2 s
 空间限制: 256000 KB
 题目等级 : 大师 Master
 
 
题目描述 Description

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

输入描述 Input Description

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

输出描述 Output Description

将取数的最大总和输出

样例输入 Sample Input

3 3
1 2 3
3 2 3
2 3 1

样例输出 Sample Output

11

数据范围及提示 Data Size & Hint

n,m<=30

【题解】:最大点权独立集

黑白染色,S到X集合中的点边容量为该点权值,Y到T同,不能同时取的两个格子连一条无穷大的边,结果是所有格子权值和减去最小割

//同题:【tyvj1338】QQ农场

#include<cstdio>
#include<iostream>
using namespace std;
const int N=210,M=1e5+10;
const int inf=0x3f3f3f3f;
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
struct node{
    int v,next,cap;
}e[M*10];int tot=1;
int n,m,num,S,T,id[N][N],mp[N][N],head[M],dis[M],q[M*10];
void add(int x,int y,int z){
    e[++tot].v=y;e[tot].cap=z;e[tot].next=head[x];head[x]=tot;
    e[++tot].v=x;e[tot].cap=0;e[tot].next=head[y];head[y]=tot;
}
bool inside(int x,int y){
    return x>0&&x<=n&&y>0&&y<=m;
}
bool bfs(){
    for(int i=S;i<=T;i++) dis[i]=inf;
    int h=0,t=1;q[t]=S;dis[S]=0;
    while(h!=t){
        int x=q[++h];
        for(int i=head[x];i;i=e[i].next){
            int v=e[i].v;
            if(e[i].cap&&dis[v]>dis[x]+1){
                dis[v]=dis[x]+1;
                if(v==T) return 1;
                q[++t]=v;
            }
        }
    }
    return dis[T]<inf;
}
int dfs(int x,int f){
    if(x==T) return f;
    int used=0,t;
    for(int i=head[x];i;i=e[i].next){
        int v=e[i].v;
        if(e[i].cap&&dis[v]==dis[x]+1){
            t=dfs(v,min(f,e[i].cap));
            e[i].cap-=t;e[i^1].cap+=t;
            used+=t;f-=t;
            if(!f) return used;
        }
    }
    dis[x]=0;
    return used;
}
int dinic(){
    int res=0;
    while(bfs()) res+=dfs(S,inf);
    return num-res;
}
void mapping(){
    int cnt=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            id[i][j]=++cnt;
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if((i+j)&1^1){
                add(S,id[i][j],mp[i][j]);
                for(int k=0;k<4;k++){
                    int nx=i+dx[k],ny=j+dy[k];
                    if(inside(nx,ny)) add(id[i][j],id[nx][ny],inf);
                }
            }
            else add(id[i][j],T,mp[i][j]);
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);S=0;T=n*m+1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%d",&mp[i][j]);num+=mp[i][j];
        }
    }
    mapping();
    printf("%d",dinic());
    return 0;
}
原文地址:https://www.cnblogs.com/shenben/p/6260496.html