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


    Description

    在一个有$m; imes;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

    $n,m<50$.

    Solution

    将棋盘黑白染色,使相邻格子颜色不同,黑色格子为集合$x$中的点,白色格子为集合$y$中的点.

    从$s$向$x_i$连一条容量为格子中数值的有向边.

    从$x_i$向$y_j$连一条容量为$+infty$的有向边($x_i,y_j$有公共边).

    从$y_i$向$t$连一条容量为格子中数值的有向边.

    求最大点权独立集.

    最大点权独立集=总点权-最小点权覆盖=总点权-最小割=总点权-最大流。

    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define M 4
    #define N 50
    using namespace std;
    struct graph{
        int nxt,to,f;
    }e[N*N];
    int a[N][N],b[N][N],g[N*N],dep[N*N],n,m,s,t,cnt,sum;
    int x[M]={0,0,-1,1},y[M]={-1,1,0,0};
    queue<int> q;
    inline void addedge(int x,int y,int f){
        e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;e[cnt].f=f;
    }
    inline void adde(int x,int y,int f){
        addedge(x,y,f);addedge(y,x,0);
    }
    inline bool bfs(int u){
        memset(dep,0,sizeof(dep));
        dep[u]=1;q.push(u);
        while(!q.empty()){
            u=q.front();q.pop();
            for(int i=g[u];i;i=e[i].nxt)
                if(e[i].f>0&&!dep[e[i].to]){
                    q.push(e[i].to);
                    dep[e[i].to]=dep[u]+1;
                }
        }
        return dep[t];
    }
    inline int dfs(int u,int f){
        int ret=0;
        if(u==t) return f;
        for(int i=g[u],d;i&&f;i=e[i].nxt)
            if(e[i].f>0&&dep[e[i].to]>dep[u]){
                d=dfs(e[i].to,min(f,e[i].f));
                e[i].f-=d;e[i^1].f+=d;ret+=d;f-=d;
            }
        return ret;
    }
    inline int dinic(){
        int ret=0;
        while(true){
            if(!bfs(s)) return ret;
            ret+=dfs(s,sum);
        }
    }
    inline void Aireen(){
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;++i)
            for(int j=0;j<m;++j){
                scanf("%d",&a[i][j]);
                sum+=a[i][j];b[i][j]=++cnt;
            }
        cnt=1;s=n*m+1;t=s+1;
        for(int i=0;i<n;++i)
            for(int j=i&1;j<m;j+=2){
                adde(s,b[i][j],a[i][j]);
                for(int k=0,u,v;k<M;++k){
                    u=i+x[k];v=j+y[k];
                    if(u>=0&&u<n&&v>=0&&v<m)
                        adde(b[i][j],b[u][v],sum);
                }
            }
        for(int i=0;i<n;++i)
            for(int j=i&1^1;j<m;j+=2)
                adde(b[i][j],t,a[i][j]);
        printf("%d
    ",sum-dinic());
    }
    int main(){
        freopen("grid.in","r",stdin);
        freopen("grid.out","w",stdout);
        Aireen();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    题解:SPOJ1026 Favorite Dice
    机器学习笔记
    机器学习第二次作业
    机器学习第一次作业
    2019软工实践总结作业
    软工2019作业6——软件评测
    2019软工作业五-实现师门树
    软件工程 “校园汇” 个人IDEA竞选分析与总结
    软工2019作业四
    软工2019作业三
  • 原文地址:https://www.cnblogs.com/AireenYe/p/6240943.html
Copyright © 2020-2023  润新知