国家集训队 部落战争 网络流最小路径覆盖 洛谷P2172
step1:
题目大意
有一张M x N的网格图,有一些点为“ * ”可以走,有一些点为“ x ”不能走,每走一步你都可以移动R * C 个格子(参考象棋中马的走法),且不能回头,已经走过的点不能再被走第二次。
每次,你可以从任意“ * ”能走的点出发,求至少要多少次才能走完所有的能走的点。
step2:
题意翻译
那么题意便可以转化为: 一条路径可以看做从任意一个没有到达过的可通过的点出发到任意一个其他的可以通过却没有被到达过的点的一条路径, 要使每个点都被经过, 并且每个点都只能被经过一次。
实现方法:
乍一看,这不就是网络流/二分图中的最小路径覆盖吗! 实现起来也不难。
网格中的每个点,我们都抽象成网络流中对应的两个点:<i, a> <i, b>。这两个分出来的点可以这么理解:a点即代表他自己,b点即代表前往的目标。如果我们可以从一个点 i 到达另外一个点 j ,我们就把<i, a> 连向 <j, b>,表明从 i -> j。由于每个点都只能被走一次,所以我们的边权都是1。(流量满了即代表这个点已经被走过,不可再被走)。
最后,考虑如何求得结果。最开始,我们有可以到达的点的数量这么多条边(不可到达的点那条路径根本就不可能是通的,所以直接忽略。连上源汇点只是为了方便懒得特判和寻找对应的编号)。每连上一组 <i, a> <j, b> ,其实就代表着我们把二者的路径合并了。
我们又知道一个定理:最小点(在这个题中是路径)覆盖 = 点数 - 最大独立集 = 点数 - 最小割 = 点数 - 最大流。
所以,将最大流求出来,然后操作一下点数即可。
千少万少,代码不能少
#include <bits/stdc++.h>
using namespace std;
#define N 100010
#define INF (~0u>>1)
#define isdigit(c) ((c)>='0'&&(c)<='9') inline int read(){
int x = , s = ;
char c = getchar();
while(!isdigit(c)){
if(c == '-')s = -;
c = getchar();
}
while(isdigit(c)){
x = (x << ) + (x << ) + (c ^ '');
c = getchar();
}
return x * s;
} struct node_bian{
int u, v, w;
int next;
}t[N];
int f[N]; int R , C;
int s, ht, fx[], fy[];
int n, m;
int deth[N];
int ma[][], sum = ;
int cur[N]; int bian = -; /*一定从 -1 开始,之后寻找反边的 ^ 操作*/
inline void add(int u, int v, int w){
t[++bian] = (node_bian){u, v, w, f[u]}, f[u] = bian;
t[++bian] = (node_bian){v, u, , f[v]}, f[v] = bian;
return ;
} queue <int> q;
bool bfs(){
memset(deth, , sizeof(deth));
while(!q.empty())q.pop(); /*记得清空队列*/
deth[s] = ;
q.push(s);
while(!q.empty()){
int now = q.front();
q.pop();
for(int i = f[now]; ~i;i = t[i].next){
int v = t[i].v, u = t[i].u;
if(!deth[v] && t[i].w > ){ /*w > 0 不可忘*/
deth[v] = deth[u] + ;
q.push(v);
}
}
}
return deth[ht] != ;
} int dfs(int now, int flow){
if(now == ht || !flow) return flow;
for(int& i = cur[now]; ~i;i = t[i].next){
int v = t[i].v, u = t[i].u, w = t[i].w;
if(deth[v] == deth[u] + && w > ){
int di = dfs(v, min(flow, w));
if(di > ){
t[i].w -= di;
t[i^].w += di;
return di;
}
}
}
return ;
} int Dicnic(){
int ans = ;
while(bfs()){
memcpy(cur, f, sizeof(cur));
while(int temp = dfs(s, INF)){
ans += temp;
}
}
return ans;
} inline void clean(){ /*记得初始化*/
memset(f, -, sizeof(f));
for(register int i = ;i <= N; i++)t[i].next = -;
return ;
} int main(){
clean();
m = read(), n = read(), R = read(), C = read();
for(int i = ;i <= m; i++)
for(int j = ;j <= n;j++){
char c;
cin >> c;
ma[i][j] = (c == '.');
if(ma[i][j])sum++;
}
fx[] = R,fy[] = C, fx[] = R, fy[] = -C, fx[] = C, fy[] = R, fx[] = C, fy[] = -R;/*分清楚方向*/
s = * m * n + , ht = s + ;
for(int i = ;i <= m; i++){
for(int j = ;j <= n; j++){
add(s, (i - ) * n + j, );
add((i - ) * n + j + m * n, ht, );
if(ma[i][j]){
for(int k = ;k <= ; k++){
int r = i + fx[k], c = j + fy[k]; /*注意,x 对应的是 m, y对应的是 n,搞错就完蛋*/
if(r >= && r <= m && c >= && c <= n && ma[r][c])
add((i - ) * n + j, (r - ) * n + c + m * n, );/*这里是以坐标来进行编号的*/
}
}
}
}
printf("%d\n", sum - Dicnic());
return ;
}
(说实话,这题的标签怪吓人的)
国家集训队 部落战争 网络流最小路径覆盖 洛谷P2172的更多相关文章
- P2172 [国家集训队]部落战争(最小路径覆盖)
P2172 [国家集训队]部落战争 每个点仅走一次:最小路径覆盖 套路地拆点,具体看代码中的$draw()$ 流量每增加1,意味着一支军队可以多走一格,代价减少1 最后答案即为总点数$-dinic() ...
- P2172 [国家集训队]部落战争 二分图最小不相交路径覆盖
二分图最小不相交路径覆盖 #include<bits/stdc++.h> using namespace std; ; ; ; ], nxt[MAXM << ], f[MAXM ...
- 【洛谷】4304:[TJOI2013]攻击装置【最大点独立集】【二分图】2172: [国家集训队]部落战争【二分图/网络流】【最小路径覆盖】
P4304 [TJOI2013]攻击装置 题目描述 给定一个01矩阵,其中你可以在0的位置放置攻击装置. 每一个攻击装置(x,y)都可以按照“日”字攻击其周围的8个位置(x-1,y-2),(x-2,y ...
- [国家集训队]部落战争 最大流 BZOJ2150
题目描述 lanzerb的部落在A国的上部,他们不满天寒地冻的环境,于是准备向A国的下部征战来获得更大的领土. A国是一个M*N的矩阵,其中某些地方是城镇,某些地方是高山深涧无人居住.lanzerb把 ...
- 洛谷P2172 [国家集训队]部落战争 题解
题目链接:https://www.luogu.org/problemnew/show/P2172 分析: 不要被[国家集训队]的标签吓到,其实这题不是很难. 本题可以对比P4304 [TJOI2013 ...
- BZOJ-2150部落战争(最小路径覆盖)
2150: 部落战争 Time Limit: 10 Sec Memory Limit: 259 MB Description lanzerb的部落在A国的上部,他们不满天寒地冻的环境,于是准备向A国 ...
- [bzoj2150]部落战争_二分图最小路径覆盖
部落战争 bzoj-2150 题目大意:题目链接. 注释:略. 想法: 显然是最小路径覆盖,我们知道:二分图最小路径覆盖等于节点总数-最大匹配. 所以我们用匈牙利或者dinic跑出最大匹配,然后用总结 ...
- BZOJ2150部落战争——最小路径覆盖
题目描述 lanzerb的部落在A国的上部,他们不满天寒地冻的环境,于是准备向A国的下部征战来获得更大的领土. A国是一 个M*N的矩阵,其中某些地方是城镇,某些地方是高山深涧无人居住.lanzerb ...
- 【最小路径覆盖】【二分图】【最大流】【Dinic】bzoj2150 部落战争
裸的最小路径覆盖. 把每个点拆点,变成二分图. 对于可以连边的点对(i,j):i->j'(1); 对于任意一点i,若i点为'.':S->i(1),i'->T(1); 答案为所有'.' ...
随机推荐
- 题解 CF545A 【Toy Cars】
题目传送门 太弱了,只能写写A题的题解 题意 给你一个 $n·n$ 的矩阵,翻车分三种情况: 如果 $a_i,_j=1$ ,记录第 $i$ 辆车 如果 $a_i,_j=2$ ,记录第 $j$ 辆车 如 ...
- IoTClientTool自动升级更新
IoTClientTool是什么 IoTClientTool是什么,IoTClientTool是IoTClient开源组件的可视化操的作实现.方便对plc设备和ModBusRtu.BACnet.串口等 ...
- 带"反悔"的贪心-超市
题面:https://www.acwing.com/problem/content/description/147/ 超市里有N件商品,每个商品都有利润pi和过期时间di,每天只能卖一件商品,过期商品 ...
- 201771010113 李婷华 《面向对象程序设计(java)》第十五周总结
一.理论知识部分 JAR文件 Java程序的打包:程序编译完成后,程序员将.class文件压缩打包为.jar文件后,GUI界面程序就可以直接双击图标运行. .jar文件(Java归档)既可以包含类文件 ...
- 某科学的PID算法学习笔记
最近,在某社团的要求下,自学了PID算法.学完后,深切地感受到PID算法之强大.PID算法应用广泛,比如加热器.平衡车.无人机等等,是自动控制理论中比较容易理解但十分重要的算法. 下面是博主学习过程中 ...
- leeCode刷题 lc184
Employee 表包含所有员工信息,每个员工有其对应的 Id, salary 和 department Id. +----+-------+--------+--------------+| Id ...
- CentOS7编译和安装GCC7.5
CentOS7编译和安装GCC7.5 一. 环境介绍: CentOS7 虚拟机连上了互联网(为什么要强调这点呢,因为CentOS7每次进入系统,都需要手动点击右上角的Connect,才能连上互联 ...
- 《C程序设计语言》 练习3-3
问题描述 编写expand(s1,s2),将字符串s1中类似于a-z类的速记符号在字符串s2中扩展为等价的完整列表abc.....xyz.该函数可以处理大小写字母和数字,并可以处理a-b-c,a-z0 ...
- leetcode 第184场周赛第一题(数组中的字符串匹配)
一.函数的运用 1,strstr(a,b); 判断b是否为a的子串,如果是,返回从b的开头开始到a的结尾 如“abcdefgh” “de” 返回“defgh”: 如果不是子串,返回NULL: 2,me ...
- 垃圾收集器与内存分配策略——深入理解Java虚拟机 笔记二
在本篇中,作者大量篇幅介绍了当时较为流行的垃圾回收器,但现在Java 14都发布了,垃圾收集器也是有了很大的进步和发展,因此在此就不再对垃圾收集器进行详细的研究.但其基本的算法思想还是值得我们参考学习 ...