国家集训队 部落战争 网络流最小路径覆盖 洛谷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); 答案为所有'.' ...
随机推荐
- Java种sleep和wait的区别
1,sleep方法是Thread类的静态方法,wait()是Object超类的成员方法 2,sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时 ...
- 一条SQL的执行流程
- jquery注册页面的判断及代码的优化
今天主要负责完成注册页面的jquery代码的写入与优化,基本代码和登录页面差不多,复制修改一下代码就行了,主要区别在于多了一个重复密码与密码是否一致的判断,刚开始写出来的代码导致每个框的后面都追加重复 ...
- ZOOM火速收购加密公司Kaybase 能否补齐安全短板?
近日,一直因为安全漏洞饱受批评的云视频会议协作工具ZOOM,,其公司全资收购一家初创企业Kaybase,以加强ZOOM系统的隐私保护和安全性. Kaybase公司官网 2020年年初,随着疫情的蔓 ...
- 超过百万的StackOverflow Flutter 问题-第二期
老孟导读:一个月前分享的<超过百万的StackOverflow Flutter 问题-第一期>受到很多朋友的喜欢,非常感谢大家的支持,在文章末尾有第一期的链接,希望此文能对你有所帮助. N ...
- 向大家介绍我的新书:《基于股票大数据分析的Python入门实战》
我在公司里做了一段时间Python数据分析和机器学习的工作后,就尝试着写一本Python数据分析方面的书.正好去年有段时间股票题材比较火,就在清华出版社夏老师指导下构思了这本书.在这段特殊时期内,夏老 ...
- vue父子组件之间相互传值
1. 子组件使用父组件方法,并向父组件传值 子组件代码 <template> <div class="menu"> <div class=" ...
- ASHRAE KAGGLE大能源预测(前三名方案总结+相关知识点讲解+python实现)
@ 目录 1 概述 2 处理思想学习 2.1 移除异常值 2.2 缺失值 2.3 目标函数 2.4 特征工程 2.4.1 Savitzky-Golay filter 2.4.2 Bayesian ta ...
- 剑指Offer01之二维数组中查找目标数
剑指Offer之二维数组中查找目标数 题目描述 在一个二维数组中(每个一维数组的长度相等),每一行都是从左到右递增的顺序排序,每一列都是从上到下递增的顺序排序,输入这样一个二维数组和一个整数,判断 ...
- 4.1Go if-else
1. Go if-else Golang程序的流程控制决定程序如何执行,主要有三大流程控制,顺序控制.分支控制.循环控制. 条件语句需要定义一个或多个条件,并且对条件测试的true或false来决定是 ...