P2774 方格取数问题 网络最大流 割

Posted ckxkexing

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2774 方格取数问题 网络最大流 割相关的知识,希望对你有一定的参考价值。

P2774 方格取数问题:https://www.luogu.org/problemnew/show/P2774

题意:  

  给定一个矩阵,取出不相邻的数字,使得数字的和最大。

思路:

  可以把方格分成两个部分,横坐标和纵坐标和为奇数的一组,和为偶数的一组,超级源点向偶数一组连容量为格点数字大小的边,奇数一组向超级汇点连容量为格点大小的边。然后两组间相临的点连容量为无穷的边。

  跑出这个图的最大流,相当于是最小割,就是去掉了最少的部分使得网络不流通。因此答案就是sum - dinic();

技术图片
#include <algorithm>
#include  <iterator>
#include  <iostream>
#include   <cstring>
#include   <cstdlib>
#include   <iomanip>
#include    <bitset>
#include    <cctype>
#include    <cstdio>
#include    <string>
#include    <vector>
#include     <stack>
#include     <cmath>
#include     <queue>
#include      <list>
#include       <map>
#include       <set>
#include   <cassert>

using namespace std;
#define lson (l , mid , rt << 1)
#define rson (mid + 1 , r , rt << 1 | 1)
#define debug(x) cerr << #x << " = " << x << "
";
#define pb push_back
#define pq priority_queue



typedef long long ll;
typedef unsigned long long ull;
//typedef __int128 bll;
typedef pair<ll ,ll > pll;
typedef pair<int ,int > pii;
typedef pair<int,pii> p3;

//priority_queue<int> q;//这是一个大根堆q
//priority_queue<int,vector<int>,greater<int> >q;//这是一个小根堆q
#define fi first
#define se second
//#define endl ‘
‘

#define OKC ios::sync_with_stdio(false);cin.tie(0)
#define FT(A,B,C) for(int A=B;A <= C;++A)  //用来压行
#define REP(i , j , k)  for(int i = j ; i <  k ; ++i)
#define max3(a,b,c) max(max(a,b), c);
#define min3(a,b,c) min(min(a,b), c);
//priority_queue<int ,vector<int>, greater<int> >que;

const ll mos = 0x7FFFFFFF;  //2147483647
const ll nmos = 0x80000000;  //-2147483648
const int inf = 0x3f3f3f3f;
const ll inff = 0x3f3f3f3f3f3f3f3f; //18
const int mod = 1000000007;
const double esp = 1e-8;
const double PI=acos(-1.0);
const double PHI=0.61803399;    //黄金分割点
const double tPHI=0.38196601;


template<typename T>
inline T read(T&x){
    x=0;int f=0;char ch=getchar();
    while (ch<0||ch>9) f|=(ch==-),ch=getchar();
    while (ch>=0&&ch<=9) x=x*10+ch-0,ch=getchar();
    return x=f?-x:x;
}
/*-----------------------showtime----------------------*/

            const int maxn = 109;
            int n,m;
            int mp[maxn][maxn];

            struct E{
                int u,v,val;
                int nxt;
            }edge[maxn*maxn*2];
            int head[maxn*maxn],gtot = 0;
            void addedge(int u,int v,int val){
                edge[gtot].u = u;
                edge[gtot].v = v;
                edge[gtot].val = val;
                edge[gtot].nxt = head[u];
                head[u] = gtot++;

                edge[gtot].u = v;
                edge[gtot].v = u;
                edge[gtot].val = 0;
                edge[gtot].nxt = head[v];
                head[v] = gtot++;
            }
            int dis[maxn*maxn];
            bool bfs(int s,int t){
                memset(dis, inf, sizeof(dis));
                dis[s] = 0; 
                queue<int>que;  que.push(s);
                while(!que.empty()){
                    int u = que.front(); que.pop();
                    for(int i = head[u]; ~i; i = edge[i].nxt){
                        int v = edge[i].v; 
                        if(edge[i].val > 0 && dis[v] >= inf){
                            dis[v] = dis[u] + 1;
                            que.push(v);
                        }
                    }
                }
                return dis[t] < inf;
            }   

            int dfs(int u,int t,int maxflow){
                if(u == t || maxflow == 0) return maxflow;

                for(int i=head[u]; ~i; i = edge[i].nxt){
                    int v = edge[i].v, val = edge[i].val;
                    if(dis[v] == dis[u] + 1 && val > 0){
                        int flow = dfs(v, t,min(val, maxflow));
                        if(flow > 0){
                            edge[i].val -= flow;
                            edge[i^1].val += flow;
                            return flow;
                        }
                    }
                }
                return 0;
            }

            int dinic(int s,int t){
                int flow = 0;
                while(bfs(s,t)){
                    
                    while(int f = dfs(s,t,inf)) flow += f;

                }
                return flow;
            }
            int cal(int i,int j){
                return (i-1) * m + j;
            }
            int nx[4][2] = {
                {1,0},{0,1},{-1,0},{0,-1}
            };
int main(){
            scanf("%d%d", &n, &m); 
            int s = 0, t = n*m+1;
            int sum = 0;
            memset(head, -1, sizeof(head));
            for(int i=1; i<=n; i++){
                for(int j=1; j<=m; j++){
                    scanf("%d", &mp[i][j]);
                    if((i + j) % 2 == 0) addedge(s, cal(i,j), mp[i][j]);
                    else addedge(cal(i,j), t, mp[i][j]);
                    sum += mp[i][j];
                }
            }
            for(int i=1; i<=n; i++){
                for(int j=1; j<=m; j++){

                    if((i+j)% 2) continue;

                    for(int k=0; k< 4; k++){
                        int x = i + nx[k][0];
                        int y = j + nx[k][1];
                        if(x < 1 || x >n || y < 1 || y > m)continue;
                        addedge(cal(i,j), cal(x,y), inf);
                    }
                }
            }
            cout<<sum - dinic(s,t)<<endl;
            return 0;
}
View Code

 

以上是关于P2774 方格取数问题 网络最大流 割的主要内容,如果未能解决你的问题,请参考以下文章

P2774 方格取数问题(最小割)

P2774 方格取数问题 网络流

P2774 方格取数问题 网络流重温

luogu P2774 方格取数问题

734. [网络流24题] 方格取数问题 二分图点权最大独立集/最小割/最大流

LiberOJ #6007. 「网络流 24 题」方格取数 最小割 最大点权独立集 最大流