国家集训队 部落战争 网络流最小路径覆盖 洛谷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); 答案为所有'.' ...
随机推荐
- 图论--最短路--SPFA模板(能过题,真没错的模板)
[ACM常用模板合集] #include<iostream> #include<queue> #include<algorithm> #include<set ...
- lh的简单图论
lh的简单图论 http://10.64.70.166/problem/1112 lh的简单图论 Description 众所周知,集训队的lh同学txdy,有一天他在写着代码,突然哼起了rapr ...
- 区间dp C - Two Rabbits
C - Two Rabbits 这个题目的意思是,n块石头围一圈.一只兔子顺时针,一只兔子逆时针(限制在一圈的范围内). 这个题目我觉得还比较难,不太好想,不过后来lj大佬给了我一点点提示,因为是需要 ...
- Excel非常规快捷键
Windows+V,调出剪贴板,是常规快捷键,鼠标右键-W-F,新建文件夹,这是非常规快捷键. 掌握Excel大半菜单和三五十快捷键,Excel也算入门了.对Excel快捷键的学习,其一是常规快捷键, ...
- 最简单的手机预览WEB移动端网页的方法
网上看了很多关于该问题的解决办法,各种各样的都有,个人也测试了一些, 最后总结出一个最简单且实用的方法. 1.安装nodejs node官网下载对应版本的nodejs,安装好了之后,在node.js执 ...
- 1.1UML图分类
用例图 表现方式 是谁用软件 软件的功能 类图 描述类内部关系和类之间关系, 关系的强弱顺序泛化=实现>组合>聚合>关联>依赖 泛化:继承关系,指定了子类如何继承父类所有特征和 ...
- android学习流程确立
也是摘抄自网上,先打个基础吧,以后有更新,再更改. 确定学习路线:向着中级工程师奋斗Android入门的时候,需要有一本入门书,好好学习书中的内容,同时花一年时间把Android官方文档中的train ...
- 如何在Github快速找到资源(资源快速检索)
github 资源检索 Github上的资源如漫天星辰,如果没有技巧,盲目的瞎找,想找到自己想要学习的的知识和资源如大海捞针!!!! 掌握正确的方法,可以说是"妈妈再也不用担心,你找不到代码 ...
- Spring全家桶之SpringMVC(三)
Spring MVC单个接收表单提交的数据 单个接收表单提交的参数 在实际开发中通过会在spring MVC的Controller里面接收表单提交过来的参数,这块代码该怎么去编写呢? 示例: 编写 ...
- Redis学习笔记(九) AOF持久化
除了RDB持久化功能之外,Redis还提供了AOF持久化功能.与RDB持久化通过保存数据库中的键值对来记录数据库状态不同,AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的. 服务 ...