P2774 方格取数问题 网络流
题目:
P2774 方格取数问题
题目背景
none!
题目描述
在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数。现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大。试设计一个满足要求的取数算法。对于给定的方格棋盘,按照取数要求编程找出总和最大的数。
输入输出格式
输入格式:
第 1 行有 2 个正整数 m 和 n,分别表示棋盘的行数和列数。接下来的 m 行,每行有 n 个正整数,表示棋盘方格中的数。
输出格式:
程序运行结束时,将取数的最大总和输出
输入输出样例
说明
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 方格取数问题 网络流的更多相关文章
- P2774 方格取数问题 网络流重温
P2774 方格取数问题 这个题目之前写过一次,现在重温还是感觉有点难,可能之前没有理解透彻. 这个题目要求取一定数量的数,并且这些数在方格里面不能相邻,问取完数之后和最大是多少. 这个很好的用了网络 ...
- P2774 方格取数问题(网络流)
P2774 方格取数问题 emm........仔细一看,这不是最大权闭合子图的题吗! 取一个点$(x,y)$,限制条件是同时取$(x,y+1),(x,y-1),(x+1,y),(x-1,y)$,只不 ...
- P2774 方格取数问题(最小割)
P2774 方格取数问题 一看题目便知是网络流,但由于无法建图.... 题目直说禁止那些条件,这导致我们直接建图做不到,既然如此,我们这是就要逆向思维,他禁止那些边,我们就连那些边. 我们将棋盘染色, ...
- 洛谷 P2774 方格取数问题 解题报告
P2774 方格取数问题 题目背景 none! 题目描述 在一个有 \(m*n\) 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大. ...
- P2774 方格取数问题 网络最大流 割
P2774 方格取数问题:https://www.luogu.org/problemnew/show/P2774 题意: 给定一个矩阵,取出不相邻的数字,使得数字的和最大. 思路: 可以把方格分成两个 ...
- P2774 方格取数(网络流)
https://www.luogu.com.cn/problem/P2774 在一个有 m×n 个方格的棋盘中,每个方格中有一个正整数. 现要从方格中取数,使任意2个数所在方格没有公共边,且取出的数的 ...
- P2774 方格取数问题
题目背景 none! 题目描述 在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.对于 ...
- CODEVS_1227 方格取数2 网络流 最小费用流 拆点
原题链接:http://codevs.cn/problem/1227/ 题目描述 Description 给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)现在从(1, ...
- [洛谷P2774]方格取数问题
题目大意:给你一个$n\times m$的方格,要求你从中选择一些数,其中没有相邻两个数,使得最后和最大 题解:网络流,最小割,发现相邻的两个点不可以同时选择,进行黑白染色,原点向黑点连一条容量为点权 ...
随机推荐
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(七)之Access Control
Access control ( or implementation hiding) is about "not getting it right the first time." ...
- Vue中el-form标签中的自定义el-select下拉框标签
页面写死el-select下拉框标签: 通过v-for="item in stateArr"绑定,stateArr声明在Vue组件里面的data参数里面代码如下: <el-f ...
- Git敏捷开发--stash命令
save 执行git stash,默认以commit info保存当前的stash信息 当在某个commit下,执行多次stash时,无法友好地区分每个stash的改动.save 命令可以清晰地标识每 ...
- 详解 Properties类
(请观看本人博文--<详解 I/O流>) Properties类: 概念: Properties 类的对象 是 一个持久的属性集 Properties 可 保存在流中 或 从流中加载 属性 ...
- Spring5:概念
1.Spring优点 spring是一个开源的免费的框架 spring是一个轻量级的 非入侵式的框架 控制反转(IOC).面向切面(AOP) 支持事务的处理,对框架整合的支持 **总之:spring就 ...
- EF-相关查询(逐渐完善)
linq查询方式 多条件查询 内连接 左连接 可以执行sql含事务
- xpath进阶用法
一.简介 xpath作为对网页.对xml文件进行定位的工具,速度快,语法简洁明了,在网络爬虫解析内容的过程中起到很大的作用,除了xpath的基础用法之外xpath中还存在着非常之多的进阶用法,本文将对 ...
- windows 删除非法目录
用PHP写错了路径,创建了非法目录,提示不存在该项目 复制下面 添加为批处理文件 DEL /F /A /Q \\?\%1RD /S /Q \\?\%1 将文件移入这个文件
- ZK安装、ZK配置、ZK集群部署踩过的大坑
天天采坑.来来咱们一起来填zookeeper的坑呀!! 解决坑一定要注意zk根目录下的神器,那就是logs目录下的日志, 第一坑:错误: 找不到或无法加载主类 org.apache.zookeeper ...
- 浅析 JS 中的作用域链
作用域链的形成 在 JS 中每个函数都有自己的执行环境,而每个执行环境都有一个与之对应的变量对象.例如: var a = 2 function fn () { var a = 1 console.lo ...