题面

​ 我们可以将'.'抽象为一个可以通过的点, 将'x'抽象为一个不可通过的点.

​ 那么题意便可以转化为: 一条路径可以看做从任意一个没有到达过的可通过的点出发到任意一个其他的可以通过却没有被到达过的点的一条路径, 要使每个点都被经过, 并且每个点都只能被经过一次, 这不是网络流中的最小路径覆盖吗, 大家可以去看一下魔术球问题, 魔术球问题就是最小路径覆盖的板子题.

​ 对于这种题目, 我们将图中的每一个点拆为两个点<i, a>, <i, b>, 从源点向<i, a>连边, 从<i, b>向汇点连边, 若可从点\(i\)到达点\(j\), 就从点<i, a>向点<j, b>连一条边, 由于每个点都只能出现一次, 所以这些边的容量都是1, 然后跑一遍最大流即可, 这里还要注意一下的是, 军队只能向下走, 所以八个方向变为了四个方向, 分别是(c, r), (c, -r), (r, c), (r, -c).

​ 跑完了最大流之后, 答案怎样统计呢, 我们最初每个可通过的点都是一条边, 所以最初有'.'的点数这么多条边, 我们不妨设这个数为\(sum\), 那么每次从点\(i\)向点\(j\)连边, 其实就意味着将两点之间的路径合并, 那么就会减少一条边, 我们又知道一个定理:最小点(在这个题中是路径(覆盖 = 点数 - 最大独立集 = 点数 - 最小割 = 点数 - 最大流, 所以最后的答案便是\(sum\) - \(dinic()\)的值, \(dinic()\)是一个函数, 他返回的是最大流的流量.

​ 接下来还是看代码吧, 感觉解析应该没什么人会看...

具体代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#define INF 1e9
using namespace std; int m, n, R, C, mapp[105][105], u[4], v[4], S, T, head[100005], cnt = 1, cur[100005], d[100005], vis[100005], ans, sum;
struct node
{
int to, flow, next;
} edge[1000005]; inline int read()
{
int x = 0, w = 1;
char c = getchar();
while(c < '0' || c > '9') { if (c == '-') w = -1; c = getchar(); }
while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return x * w;
} inline void add(int u, int v, int w)
{
edge[++cnt] = { v, w, head[u] }; head[u] = cnt;
edge[++cnt] = { u, 0, head[v] }; head[v] = cnt;
} bool bfs()
{
memset(d, 0, sizeof(d)); d[S] = 1;
queue<int> q; q.push(S);
while(!q.empty())
{
int u = q.front(); q.pop();
for(int i = head[u]; i; i = edge[i].next)
{
int v = edge[i].to;
if(!d[v] && edge[i].flow > 0) { d[v] = d[u] + 1; q.push(v); }
}
}
return d[T];
} int dfs(int u, int a)
{
if(u == T || !a) return a;
int flow = 0;
for(int &i = cur[u]; i; i = edge[i].next)
{
int v = edge[i].to;
if(d[v] == d[u] + 1 && edge[i].flow > 0)
{
int f = dfs(v, min(a, edge[i].flow));
a -= f; flow += f; edge[i].flow -= f; edge[i ^ 1].flow += f;
}
if(!a) break;
}
if(a) d[u] = -1;
return flow;
} int dinic()
{
int flow = 0;
while(bfs())
{
memcpy(cur, head, sizeof(head));
flow += dfs(S, INF);
}
return flow;
} int main()
{
m = read(); n = read(); R = read(); C = read();
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
{
char c; cin>>c;
mapp[i][j] = (c == 'x');
if(mapp[i][j] == 1) sum++;
}
u[0] = C; u[1] = C; u[2] = R; u[3] = R; v[0] = R; v[1] = -R; v[2] = -C; v[3] = C;
S = 2 * m * n + 1; T = S + 1;
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
{
add(S, (i - 1) * n + j, 1);
add((i - 1) * n + j + m * n, T, 1);
if(!mapp[i][j])
for(int k = 0; k < 4; k++)
{
int x = i + u[k], y = j + v[k];
if(x >= 1 && x <= m && y >= 1 && y <= n && !mapp[x][y]) add((i - 1) * n + j, (x - 1) * n + y + m * n, 1);
}
}
printf("%d\n", m * n - sum - dinic());
return 0;
}

​ 话说为啥我自己的博客二级标题总是显示不出来呢

[luogu2172] 部落战争的更多相关文章

  1. BZOJ2150: 部落战争

    题解: 把每个点拆成入点和出点,因为必须经过一次且只能经过一次.所以在两个点之间连一条上界=下界=1的边. 然后再s到每个入点连边,每个出点向t连边,点与点之间... 求最小流就可以过了... (感觉 ...

  2. BZOJ 2150: 部落战争 最大流

    2150: 部落战争 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php? ...

  3. BZOJ-2150部落战争(最小路径覆盖)

    2150: 部落战争 Time Limit: 10 Sec  Memory Limit: 259 MB Description lanzerb的部落在A国的上部,他们不满天寒地冻的环境,于是准备向A国 ...

  4. 【BZOJ5317】[JSOI2018]部落战争(凸包,闵可夫斯基和)

    [BZOJ5317][JSOI2018]部落战争(凸包,闵可夫斯基和) 题面 BZOJ 洛谷 题解 很明显我们只需要两个凸包\(A,B\). 假设询问给定的方向向量是\(v\). 那么现在就是判断\( ...

  5. 【洛谷】4304:[TJOI2013]攻击装置【最大点独立集】【二分图】2172: [国家集训队]部落战争【二分图/网络流】【最小路径覆盖】

    P4304 [TJOI2013]攻击装置 题目描述 给定一个01矩阵,其中你可以在0的位置放置攻击装置. 每一个攻击装置(x,y)都可以按照“日”字攻击其周围的8个位置(x-1,y-2),(x-2,y ...

  6. 【BZOJ2150】部落战争 最小流

    [BZOJ2150]部落战争 Description lanzerb的部落在A国的上部,他们不满天寒地冻的环境,于是准备向A国的下部征战来获得更大的领土. A国是一个M*N的矩阵,其中某些地方是城镇, ...

  7. [bzoj2150]部落战争_二分图最小路径覆盖

    部落战争 bzoj-2150 题目大意:题目链接. 注释:略. 想法: 显然是最小路径覆盖,我们知道:二分图最小路径覆盖等于节点总数-最大匹配. 所以我们用匈牙利或者dinic跑出最大匹配,然后用总结 ...

  8. bzoj2150: 部落战争(匈牙利)

    2150: 部落战争 题目:传送门 题解: 辣鸡数据..毁我AC率 先说做法,很容易就可以看出是二分图匹配的最小路径覆盖(可能是之前不久刚做过类似的题) 一开始还傻逼逼的去直接连边然后准备跑floyd ...

  9. P2172 [国家集训队]部落战争(最小路径覆盖)

    P2172 [国家集训队]部落战争 每个点仅走一次:最小路径覆盖 套路地拆点,具体看代码中的$draw()$ 流量每增加1,意味着一支军队可以多走一格,代价减少1 最后答案即为总点数$-dinic() ...

随机推荐

  1. 记一次webapi传参数的问题

    .net小白一枚,经过了几个小时的研究,由于错误的写法导致后台始终接受不到前台传递过来的参数.首先看看控制器的参数 public Core.MVC.ServiceResult<DTO.Out.M ...

  2. 啰里吧嗦CountDownLatch

    java.util.concurrent Class CountDownLatch 目录 CountDownLatch 是什么 CountDownLatch是一个同步工具类,它允许一个或多个线程一直等 ...

  3. 【Linux】安装openssh-server依赖openssh-client版本错误的解决办法

    这是因为,openssh-server是依赖于openssh-clien的,ubuntu自带了openssh-client,自带的openssh-clien与所要安装的openssh-server所依 ...

  4. mysql数据库操作指令

    数据库相关 查询所有数据库 show databases; 创建数据库 create database 数据库名: 创建数据库指定字符集 create database 数据库名 character ...

  5. webpack4.0在Mac下的安装配置及踩到的坑

    一.什么是webpack是一个前端资源加载/打包工具.它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源.它做的事情是,分析你的项目结构,找到JavaScript模块以 ...

  6. Flex布局的学习经验

    做为css布局的又一种新方式,Flex拥有极强的使用效果,相比原来的float,position对元素样式的操作更加简洁,本文是我的一点学习经验和心得吧,如有错误以及不足之处,请多多指点. 好进入正题 ...

  7. JS---函数名和变量名重名

    继续作用域的问题,今天上午看了一会,下午看又看到了一个类型的题,函数名和变量名相同的问题.之前还不会觉得函数名和变量名重名了会有什么冲突.也是没有去测试过..懒了.直接贴代码: 运行之后大家猜测结果是 ...

  8. Js利用Canvas实现图片压缩

    最近做的APP项目涉及到手机拍照上传图片,因为手机拍照的图片通常都比较大,所以上传的时候就会很慢.为此,需要对图片进行压缩处理来优化上传功能.以下是具体实现: /* * 图片压缩 * img 原始图片 ...

  9. Python 在子类中调用父类方法详解(单继承、多层继承、多重继承)

    Python 在子类中调用父类方法详解(单继承.多层继承.多重继承)   by:授客 QQ:1033553122   测试环境: win7 64位 Python版本:Python 3.3.5 代码实践 ...

  10. Oracle 修改SYS、system用户密码

    Oracle 修改SYS.system用户密码 by:授客 QQ:1033553122 概念 SYS用户是Oracle中权限最高的用户,而SYSTEM是一个用于数据库管理的用户.在数据库安装完之后,应 ...