方格取数(网络流24题)

题意

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

题解

方格是常见的二分图(疑问脸)。所以考虑先染色,相邻的格子颜色不同,这样就分成了二分图,先假设全选,然后跑最小割就好了,割掉就是不选。

#include<bits/stdc++.h>
using namespace std;

const int maxn=10005;
const int maxm=40005;
const int inf=1000009;
int n,m,s,t,ans;
int cnt=1,head[maxn];
struct edge{
  int x,y,next,val;
}e[maxm<<1];

void add(int x,int y,int val){
  e[++cnt]=(edge){x,y,head[x],val};
  head[x]=cnt;
}

void add_edge(int x,int y,int val){
  add(x,y,val);
  add(y,x,0);
}

template<class T>inline void read(T &x){
  x=0;char ch=getchar();
  while(!isdigit(ch)) ch=getchar();
  while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
}

int d[maxn];

bool bfs(){
  memset(d,0,sizeof(d));
  queue<int> q;
  q.push(s);d[s]=1;
  while(!q.empty()){
    int x=q.front();
    q.pop();
    for(int i=head[x];i;i=e[i].next){
      int y=e[i].y;
      if(e[i].val&&!d[y]){
        d[y]=d[x]+1;
        if(y==t) return true;
        q.push(y);
      }
    }
  }
  return false;
}

int dfs(int x,int flow){
  if(x==t) return flow;
  int rest=flow,k;
  for(int i=head[x];i;i=e[i].next){
    int y=e[i].y;
    if(e[i].val&&d[y]==d[x]+1){
      k=dfs(y,min(rest,e[i].val));
      if(!k) d[y]=0;
      e[i].val-=k;
      e[i^1].val+=k;
      rest-=k;
    }
  }
  return flow-rest;
}

int dinic(){
  int res=0;
  while(bfs()) res+=dfs(s,0x3f3f3f);
  return res;
}

int main(){
  read(n);read(m);
  s=0;t=n*m+1;
  for(int i=1;i<=n;i++){
    int op=i&1;
    for(int j=1;j<=m;j++){
      int x;read(x);
      ans+=x;
      if(op) {
        add_edge(s,(i-1)*m+j,x);
        if(i>1) add_edge((i-1)*m+j,(i-2)*m+j,inf);
        if(i<n) add_edge((i-1)*m+j,i*m+j,inf);
        if(j>1) add_edge((i-1)*m+j,(i-1)*m+j-1,inf);
        if(j<m) add_edge((i-1)*m+j,(i-1)*m+j+1,inf);
      }
      else add_edge((i-1)*m+j,t,x);
      op^=1;
    }
  }
  ans-=dinic();
  printf("%d",ans);
}

dfs终止条件没写调了半天(笑哭)

原文地址:https://www.cnblogs.com/sto324/p/11336956.html

时间: 2024-10-14 05:38:58

方格取数(网络流24题)的相关文章

hdu 3657 最小割的活用 / 奇偶方格取数类经典题 /最小割

题意:方格取数,如果取了相邻的数,那么要付出一定代价.(代价为2*(X&Y))(开始用费用流,敲升级版3820,跪...) 建图:  对于相邻问题,经典方法:奇偶建立二分图.对于相邻两点连边2*(X&Y),源->X连边,Y->汇连边,权值w为点权. ans=总点权-最小割:如果割边是源->X,表示x不要选(是割边,必然价值在路径上最小),若割边是Y-汇点,同理:若割边是X->Y,则表示选Y点且选X点, 割为w( 2*(X&Y) ). 自己的确还没有理解其本质

BZOJ 1475: 方格取数( 网络流 )

本来想写道水题....结果调了这么久!就是一个 define 里面少加了个括号 ! 二分图最大点权独立集...黑白染色一下 , 然后建图 : S -> black_node , white_node -> T , 流量都为点权 . 然后 black_node -> white_node ( 两点有公共边 ) , 流量为 +oo , 然后 answer = ∑ w( i ) ( i ∈ V ) - maxflow --------------------------------------

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

?问题描述:在一个有m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.?编程任务:对于给定的方格棋盘,按照取数要求编程找出总和最大的数.?数据输入:由文件grid.in提供输入数据.文件第1 行有2 个正整数m和n,分别表示棋盘的行数和列数.接下来的m行,每行有n个正整数,表示棋盘方格中的数. [问题分析] 二分图点权最大独立集,转化为最小割模型,从而用最大流解决. [建模方法] 首先把棋盘黑白

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

#6007. 「网络流 24 题」方格取数 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 在一个有 m×n m \times nm×n 个方格的棋盘中,每个方格中有一个正整数. 现要从方格中取数,使任意 2 22 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法. 输入格式 文件第 1 11 行有 2 22 个正整数 m mm 和 n nn,分别表示棋盘的行数和列数

「网络流24题」 9. 方格取数问题

「网络流24题」 9. 方格取数问题 <题目链接> 二分图的最大点权独立集 建立二分图,使得每个点与其相邻的点在不同的部. 源向X部引有向边,Y部向汇引有向边,边权为点权. X部每个点到其相邻的点引有向边,边权INF,这个边的两个断电不能同时被选. 那么S-X-Y-T的任意一条增广路都表示选了两个相邻的点. 于是问题转化为求网络最小割. 最终的答案为所有点的点权和(先都选上)减去网络最小割(不能选的最小点权集). #include <algorithm> #include <

线性规划与网络流24题●09方格取数问题&amp;13星际转移问题

●(做codevs1908时,发现测试数据也涵盖了1907,想要一并做了,但因为"技术"不佳,搞了一上午) ●09方格取数问题(codevs1907  方格取数3) 想了半天,也没成功建好图: 无奈下参考题解,说是本题要求二分图点权最大独立集,然后可以由结论:"最大点权独立集 = 所有点权 - 最小点权覆盖集 = 所有点权 - 最小割集 = 所有点权 - 网络最大流"转化到求最大流(我真的很懵逼,但又感觉很有道理): 下面附上solution:(自己领悟吧) (不懂

网络流 24题 方格取数

方格取数问题 题目描述 在一个有m*n个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意2个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法. 输入格式 文件第1行有2个正整数m和n,分别表示棋盘的行数和列数.接下来的m行,每行有n个正整数,表示棋盘方格中的数.(0 <= m, n <= 30) 输出格式 取数的最大总和. 输入样例 33 1 2 3 3 2 3 2 3 1 输出样例 11 题目大意:     给出m*n的格子,相邻的格子的值不可同时取,最

线性规划与网络流9 方格取数

算法实现题 8-9 方格取数问题(习题 8-20)?问题描述:在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.?编程任务:对于给定的方格棋盘,按照取数要求编程找出总和最大的数.?数据输入:由文件 input.txt 提供输入数据.文件第 1 行有 2 个正整数 m和 n,分别表示棋盘的行数和列数.接下来的 m行,每行有 n 个正整数,表示棋盘方格中的数.?结果输出:程序运行结束时,

hdu 1565 方格取数(2)(网络流之最大点权独立集)

题目链接:hdu 1565 方格取数(2) 题意: 有一个n*m的方格,每个方格有一个数,现在让你选一些数.使得和最大. 选的数不能有相邻的. 题解: 我们知道对于普通二分图来说,最大独立点集 + 最小点覆盖集 = 总点数,类似的,对于有权的二分图来说,有: 最大点权独立集 + 最小点权覆盖集 = 总点权和, 这个题很明显是要求 最大点权独立集 ,现在 总点权 已知,我们只要求出来 最小点权覆盖集 就好了,我们可以这样建图, 1,对矩阵中的点进行黑白着色(相邻的点颜色不同),从源点向黑色的点连一