题目:

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. alg-最长不重复子串

    class Solution { public: int lengthOfLongestSubstring(const std::string& s) { int max_length = 0 ...

  2. IDEA我常用的快捷键

    IDEA快捷键 全屏编写代码:Ctrl+Shift+F12

  3. [转] [知乎] Roguelite 和 Roguelike 的区别是什么?

    编者按 本文译自 Ethan Hawkes 一篇介绍 rogue-lite 概念的文章,已获作者授权,英文原文见这里,译文首发于这里.注意本文写于 2013 年,正是 roguelite 类型的独立游 ...

  4. 【three.js第三课】鼠标事件,移动、旋转物体

    1.下载three.js的源码包后,文件夹结构如下: 2.在[three.js第一课]的代码基础上,引入OrbitControls.js文件,此文件主要用于 对鼠标的操作. 该文件位置:在文件结构中 ...

  5. S7通信协议之你不知道的事儿

    在电气学习的路上,西门子PLC应该是我的启蒙PLC,从早期的S7-300/400 PLC搭建Profibus-DP网络开始接触,到后来的S7-200Smart PLC,再到现在的S7-1200/150 ...

  6. leetcode-0543 二叉树的直径

    题目地址https://leetcode-cn.com/problems/diameter-of-binary-tree/ 递归+BFS(暴力解法) 我们可以考虑在每个节点时,都去计算该节点左子树和右 ...

  7. C#集合类型——Hashtable、Dictionary之浅谈

    Hashtable表 数组.数组集合.List集合都是通过索引来访问里面成员.哈希表则是通过键来访问成员值.键不可为空,值可为空. 比如: Hashtable  hash=new  Hashtable ...

  8. 详细分析Redis的持久化操作——RDB与AOF

    一.前言   由于疫情的原因,学校还没有开学,这也就让我有了很多的时间.趁着时间比较多,我终于可以开始学习那些之前一直想学的技术了.最近这几天开始学习Redis,买了本<Redis实战>, ...

  9. 还学的动吗? 盘点下Vue.js 3.0.0 那些让人激动的功能

    转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 原文出处:https://blog.bitsrc.io/vuejs-3-0-0-beta-features- ...

  10. python 字符与数字如何转换

    python中字符与数字相互转换用chr()即可. python中的字符数字之间的转换函数 int(x [,base ])                               将x转换为一个整 ...