[网络流24题]方格取数问题

题目:洛谷P2774、codevs1907。

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

解题思路:本题关键在建模。

把棋盘黑白染色(像国际象棋棋盘那样)。

对于黑色的,连接源点,容量为格子中的数。

对于白色的,连接汇点,容量为格子中的数。(黑白可以互换)

然后把所有黑点和相邻的白点连边,容量无穷大。

于是我们构造出了一个二分图。

题目说不能取相邻的格子,那么对于这张二分图来说,就不能让他有一条边有流经过(否则就取了两个相邻的格子了)。

于是求最小割即可。=求最大流

最后用总和减去最小割即可

C++ Code:

#include<cstdio>
#include<cstring>
#include<queue>
#define inf 0x3fffffff
std::queue<int>q;
int n,m,cnt=-1,head[20005],iter[20005],level[20005];
struct edge{
    int to,cap,nxt;
}e[10005*8];
inline int number(int x,int y){
    return(x-1)*m+y;
}
inline void addedge(int from,int to,int flow){
    ++cnt;
    e[cnt]=(edge){to,flow,head[from]};
    head[from]=cnt;
    ++cnt;
    e[cnt]=(edge){from,0,head[to]};
    head[to]=cnt;
}
void bfs(int s){
    level[s]=1;
    q.push(s);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=head[u];i!=-1;i=e[i].nxt)
        if(e[i].cap&&level[e[i].to]==-1){
            level[e[i].to]=level[u]+1;
            q.push(e[i].to);
        }
    }
}
int dfs(int u,int t,int f){
    if(u==t)return f;
    for(int& i=iter[u];i!=-1;i=e[i].nxt)
    if(e[i].cap&&level[u]<level[e[i].to]){
        int d=dfs(e[i].to,t,e[i].cap>f?f:e[i].cap);
        if(d){
            e[i].cap-=d;
            e[i^1].cap+=d;
            return d;
        }
    }
    return 0;
}
int maxflow(int s,int t){
    for(int flow=0;;){
        memset(level,-1,sizeof level);
        bfs(s);
        if(level[t]==-1)return flow;
        memcpy(iter,head,sizeof iter);
        int f;
        while(f=dfs(s,t,inf))flow+=f;
    }
}
int main(){
    scanf("%d%d",&n,&m);
    int sum=0;
    memset(head,-1,sizeof head);
    for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j){
        int t;
        scanf("%d",&t);
        sum+=t;
        int p=number(i,j);
        if((i+j)&1){
            addedge(0,p,t);
            if(i-1)addedge(p,number(i-1,j),inf);
            if(j-1)addedge(p,number(i,j-1),inf);
            if(i+1<=n)addedge(p,number(i+1,j),inf);
            if(j+1<=m)addedge(p,number(i,j+1),inf);
        }else addedge(p,n*m+1,t);
    }
    return!printf("%d\n",sum-maxflow(0,n*m+1));
}

 

posted @ 2018-01-16 20:19  Mrsrz  阅读(282)  评论(0编辑  收藏  举报