P2774 方格取数问题

这个题目之前写过一次,现在重温还是感觉有点难,可能之前没有理解透彻。

这个题目要求取一定数量的数,并且这些数在方格里面不能相邻,问取完数之后和最大是多少。

这个很好的用了网络流的最大独立集。

根据位置把这些数分成了两个独立集,两个独立集的意思是这两个集合之间有关系,但是集合内部没有任何关系,

所以是两个独立集。

分成独立集之后,我们就要建图连边,这些都很好做,但是为什么答案就是  所有数之和-最小割

因为当我们跑一次最小割之和是不是让这个图没有连接了,也就是这个图不是联通的,这样的话就是说明

每一个数和他相邻的位置就没有连边了,是不是就符合要求了?

我想让这个图不连通的最小代价是不是就是最小割,

就是我对这个图其中一些点进行了取舍,最后使得这个图不连通了,所以答案就是 所有数之和-最小割。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <iostream>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 4e3 + ;
const int mod = 1e9 + ;
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 addedge(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;
scanf("%d%d", &n, &m);
ll sum = ;
int s = , t = n * m + ;
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
int x;
scanf("%d", &x);
sum += x;
if ((i + j) & ) addedge((i - )*m + j, t, x);
else addedge(s, (i - )*m + j, x);
}
}
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
if ((i + j) & ) continue;
if (i != ) addedge((i - )*m + j, (i - )*m + j, inf);
if (i != n) addedge((i - )*m + j, i*m + j, inf);
if (j != ) addedge((i - )*m + j, (i - )*m + j - , inf);
if (j != m) addedge((i - )*m + j, (i - )*m + j + , inf);
}
}
int ans = Maxflow(s, t);
printf("%lld\n", sum - ans);
return ;
}

最新文章

  1. Castle.ActiveRecord 多对多关系 引发的错误处理
  2. CSS background-position 问题
  3. AFN实现多图片上传的方法
  4. 【Unity3D游戏开发】定制新建C#文件的头描述 (三三)
  5. 【技术贴】解决vss中提交pdf下载打开空白乱码
  6. Android Camera 使用一例,视频聊天app
  7. 推荐一套.NET文档处理组件Spire.Office
  8. 剖析WPF数据绑定机制
  9. 怎么把系统装进u盘(ultraiso)
  10. extjs6中grid里放置图片
  11. python codis集群客户端(二) - 基于zookeeper对实例创建与摘除
  12. 迭代var()内置函数的时候出现RuntimeError: dictionary changed size during iteration的解决办法
  13. 从源码安装git
  14. 理解JS原型和原型链
  15. Python几周学习内容小结
  16. caffe中的若干问题
  17. diyiti.cpp
  18. Hive启动异常
  19. datatable表格框架服务器端分页查询设置
  20. 《Programming with Objective-C》第七章 Values and Collections

热门文章

  1. 树状数组模板--Color the ball
  2. AJ学IOS(09)UI之UIScrollView代理触摸实现_图片缩放
  3. 跳转语句break与continue的使用环境
  4. Android电池信息获取
  5. testlink数据表分析
  6. python 携程asyncio实现高并发示例1
  7. 数据挖掘入门系列教程(十点五)之DNN介绍及公式推导
  8. 全国315个城市,用python爬取肯德基老爷爷的店面信息
  9. 20199308《Linux内核原理与分析》第十一周作业
  10. 2019-2020-1 20199310《Linux内核原理与分析》第六周作业