题目:

P2774 方格取数问题

题目背景

none!

题目描述

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

输入输出格式

输入格式:

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

输出格式:

程序运行结束时,将取数的最大总和输出

输入输出样例

输入样例#1: 复制

3 3
1 2 3
3 2 3
2 3 1
输出样例#1: 复制

11

说明

m,n<=100

这个题目推荐博客:https://blog.csdn.net/qq_38944163/article/details/81218555

这个博客写的很好,这个题目是一个二分图的最大独立集。

这个是让我们在一个方格中选取数字,题目限制就是共享同一个边的两个数不能取,这个题目一开始很难想到用二分图的最大独立集。

那我们就跟着之前推荐的博客思路走一下,首先你要将相邻的分开,我们可以找一个办法把这些数分成两个部分,

如果两个数同在一个部分则说明他们一定不相邻,不在一个部分则可能相邻。

根据这个原则再根据题意,我们发现,如果两个数的奇偶性相同则一定不相邻,反之则可能相邻,就这样我们把这个方格数字提取出来分成了两个部分。

再对两个部分的数字进行处理,第一部分的数字和s相连权值为这个数值的大小,第二部分的和t相连权值为这个数值的大小,如果这两个部分的数字是相邻就连一条线,这个线的边权是inf。

权值为inf的原因是不确定第一部分和s相连的权值。

然后我们要求如果连了线,那么就不能放在一起,意思是说这个图一定最后是不连通的,这个我们就想到了割。

答案就是 ans=所有数字之和 - 割

为了ans尽量大,所以这个割应该尽量小,所以 ans=所有数字之和 - 最小割(最大流)

知道了这里,就可以跑模板了,但是呢,还是感觉会有一点不能理解。

你可以这么想,我要这个不连通,跑了一个最大流之后,有一些管道就已经满了,如果满了,这个管道满了(假设是连接s) 那么另外一个连接t的管道可能没有满

这个时候最大值只会加上这个更小一点的数,就相当于我在这两个相邻的数之间选了一个更小的数出去,这个是不是就满足我们的要求了。

这个跑最大流,就有点像短板效应了,就是就是在两块板子里面选了更短的一块加起来,这个会不会比较好理解,

这些都是最小割里面的内容了,不会的可以取看看我的另一篇博文:

P2762 太空飞行计划问题 网络流

这个就讲了一点点最小割的东西。

#include <cstdio>
#include <cstdlib>
#include <queue>
#include <vector>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define inf 0x3f3f3f3f
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5 + ;
struct edge
{
int u, v, c, f;
edge(int u, int v, int c, int f) :u(u), v(v), c(c), f(f) {}
};
vector<edge>e;
vector<int>G[maxn];
int level[maxn];//BFS分层,表示每个点的层数
int iter[maxn];//当前弧优化
int m;
void init(int n)
{
for (int i = ; i <= n; i++)G[i].clear();
e.clear();
}
void add(int u, int v, int c)
{
e.push_back(edge(u, v, c, ));
e.push_back(edge(v, u, , ));
m = e.size();
G[u].push_back(m - );
G[v].push_back(m - );
}
void BFS(int s)//预处理出level数组
//直接BFS到每个点
{
memset(level, -, sizeof(level));
queue<int>q;
level[s] = ;
q.push(s);
while (!q.empty())
{
int u = q.front();
q.pop();
for (int v = ; v < G[u].size(); v++)
{
edge& now = e[G[u][v]];
if (now.c > now.f && level[now.v] < )
{
level[now.v] = level[u] + ;
q.push(now.v);
}
}
}
}
int dfs(int u, int t, int f)//DFS寻找增广路
{
if (u == t)return f;//已经到达源点,返回流量f
for (int &v = iter[u]; v < G[u].size(); v++)
//这里用iter数组表示每个点目前的弧,这是为了防止在一次寻找增广路的时候,对一些边多次遍历
//在每次找增广路的时候,数组要清空
{
edge &now = e[G[u][v]];
if (now.c - now.f > && level[u] < level[now.v])
//now.c - now.f > 0表示这条路还未满
//level[u] < level[now.v]表示这条路是最短路,一定到达下一层,这就是Dinic算法的思想
{
int d = dfs(now.v, t, min(f, now.c - now.f));
if (d > )
{
now.f += d;//正向边流量加d
e[G[u][v] ^ ].f -= d;
//反向边减d,此处在存储边的时候两条反向边可以通过^操作直接找到
return d;
}
}
}
return ;
}
int Maxflow(int s, int t)
{
int flow = ;
for (;;)
{
BFS(s);
if (level[t] < )return flow;//残余网络中到达不了t,增广路不存在
memset(iter, , sizeof(iter));//清空当前弧数组
int f;//记录增广路的可增加的流量
while ((f = dfs(s, t, INF)) > )
{
flow += f;
}
}
return flow;
} int main()
{
int n, m, sum = ;
cin >> n >> m;
int s = , t = n * m + ;
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
int x;
cin >> x;
sum += x;
int ex = (i - )*m + j;
if ((i+j) & )//这个地方要注意一下,不能用ex&1
{
add(s, ex, x);
if (j + <= m) add(ex, ex + , inf);
if (i + <= n) add(ex, i*m + j, inf);
if (j - >= ) add(ex, ex - , inf);
if (i - >= ) add(ex, (i - )*m + j, inf);
}
else add(ex, t, x);
}
}
int ans = Maxflow(s, t);
printf("%d\n", sum - ans);
return ;
}

P2774 方格取数问题 网络流的更多相关文章

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

    P2774 方格取数问题 这个题目之前写过一次,现在重温还是感觉有点难,可能之前没有理解透彻. 这个题目要求取一定数量的数,并且这些数在方格里面不能相邻,问取完数之后和最大是多少. 这个很好的用了网络 ...

  2. P2774 方格取数问题(网络流)

    P2774 方格取数问题 emm........仔细一看,这不是最大权闭合子图的题吗! 取一个点$(x,y)$,限制条件是同时取$(x,y+1),(x,y-1),(x+1,y),(x-1,y)$,只不 ...

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

    P2774 方格取数问题 一看题目便知是网络流,但由于无法建图.... 题目直说禁止那些条件,这导致我们直接建图做不到,既然如此,我们这是就要逆向思维,他禁止那些边,我们就连那些边. 我们将棋盘染色, ...

  4. 洛谷 P2774 方格取数问题 解题报告

    P2774 方格取数问题 题目背景 none! 题目描述 在一个有 \(m*n\) 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大. ...

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

    P2774 方格取数问题:https://www.luogu.org/problemnew/show/P2774 题意: 给定一个矩阵,取出不相邻的数字,使得数字的和最大. 思路: 可以把方格分成两个 ...

  6. P2774 方格取数(网络流)

    https://www.luogu.com.cn/problem/P2774 在一个有 m×n 个方格的棋盘中,每个方格中有一个正整数. 现要从方格中取数,使任意2个数所在方格没有公共边,且取出的数的 ...

  7. P2774 方格取数问题

    题目背景 none! 题目描述 在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.对于 ...

  8. CODEVS_1227 方格取数2 网络流 最小费用流 拆点

    原题链接:http://codevs.cn/problem/1227/ 题目描述 Description 给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)现在从(1, ...

  9. [洛谷P2774]方格取数问题

    题目大意:给你一个$n\times m$的方格,要求你从中选择一些数,其中没有相邻两个数,使得最后和最大 题解:网络流,最小割,发现相邻的两个点不可以同时选择,进行黑白染色,原点向黑点连一条容量为点权 ...

随机推荐

  1. tf.nn.max_pool 池化

    tf.nn.max_pool( value, ksize, strides, padding, data_format='NHWC', name=None ) 参数: value:由data_form ...

  2. java集合中的一个移除数据陷阱(遍历集合自身并同时删除被遍历数据)

    下面是网上的其他解释,更能从本质上解释原因:Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁. Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量 ...

  3. CentOS7安装MYCAT中间件

    MYCAT是一个被广泛使用的功能强大的开源的数据库中间件,当然他的理想不仅仅是做一个中间件.这篇文章主要记录MYCAT服务的搭建过程,下篇会继续更新MYCAT的使用配置. 本篇记录将使用CentOS7 ...

  4. AJ学IOS(20)UI之UIPickerView_点菜系统

    AJ分享,必须精品 先看效果图 ## UIPickerView控件 UIPickerView用处: 用来展示很多行(row) 很多列(component )的数据,多用于电子商务的点菜,城市选择等等. ...

  5. 基于linux或windows平台上的c/s简单通信

    linux: tcpclient.cpp #include<iostream> #include<unistd.h> #include<sys/types.h> # ...

  6. 第一节:python基础

    2020-03-29 python基础: 多种python版本,直接编码让c解释的是cpython,pypy是最快的python 编码:ascll码只能表示256种无法表示中文,utf8个根据字符长短 ...

  7. Beta-release 目标

    在第二个release开发周期中我们首要先要完成的是对第一个发布版本的优化:(之前团队在跟travis的沟通中,travis也要求我们首先要把现在已有的feature做到一个比较成熟和稳定的版本) 1 ...

  8. D - Leading and Trailing LightOJ - 1282

    题解:求n^k的前三位和后三位. 后三位直接快速幂对1000去余就可以了.前三位可以转换成浮点数来操作,也是用快速幂,我们只保留答案的前三位,当前值大于1000.0的话就除以10,直到结果小于等于10 ...

  9. C - Highways poj1751最小生成树

    The island nation of Flatopia is perfectly flat. Unfortunately, Flatopia has a very poor system of p ...

  10. CKEditor与定制

    一 开始使用 官网 基本示例: 搭建服务器(这里使用apache) 下载standard的ckeditor解压放在apache的htdocs的目录下 在htdoc下面新建index.html,写入代码 ...