国家集训队 部落战争 网络流最小路径覆盖 洛谷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); 答案为所有'.' ...
随机推荐
- 数学--数论--HDU1576 A / B(逆元)
问题描述 要求(A / B)%9973,但由于A很大,我们只被告知n(n = A%9973)(我们给定的A必能被B整除,且gcd(B,9973)= 1). 输入项 数据的第一行是一个T,表示有T组数据 ...
- 图论--树的重心(DFS) 模板
const int maxn=500005; int tot=0,n; int ans,size; int sx[maxn],head[maxn]; int vis[maxn]; struct edg ...
- 图论--BFS总结
1.关于BFS的Key_word: ①hash或状态压缩记录状态 ②状态剪枝 ③反向BFS ④双向BFS ⑤特殊初始化VIS数组 ⑥动态图的搜索 ⑦优先队列优化搜索 ⑧数位搜索 下面是一一讲解: 1 ...
- CF1335F Robots on a Grid
比较简单的倍增 但还是看了题解才会 题意 给出一个 \(n\times m\) 的网格,每个格子有颜色,\(0\) 黑 \(1\) 白,每个格子还有一个方向,表示这个格子上的机器人会向那个方向走,并保 ...
- 5) ModelSerializer(重点) 基表 测试脚本 多表关系建外键 正反查 级联 插拔式连表 序列化反序列化整合 增删查 封装response
一.前戏要做好 配置:settings.py #注册drf INSTALLED_APPS = [ # ... 'api.apps.ApiConfig', 'rest_framework', ] # ...
- P3467(矩形覆盖问题)
描述:https://www.luogu.com.cn/problem/P3467 1.考虑如果整个建筑物链是等高的,一张高为链高,宽为整个建筑物宽的海报即可完全覆盖: 2.若有两个不等高的元素组成建 ...
- while(scanf("%d",&n)!=EOF) / while(cin>>n)终止问题
问题的发现:(想要看干货可以直接跳过这段) 我最近刚了解到关于栈的用法,于是按照参考书寻找代码,并把它敲到电脑上.编译运行代码后发现无法终止,在网上查找各种资料,总结如下. 因为我的电脑是Window ...
- Mysql常用sql语句(22)- insert 插入数据
测试必备的Mysql常用sql语句系列 https://www.cnblogs.com/poloyy/category/1683347.html 前言 终于讲完基础的查询语句了...这篇讲的就是插入数 ...
- 帝国cms 批量替换 字段内容包含的 指定的 关键字 SQL命令
帝国cms 批量替换 字段内容包含的 指定的 关键字update phome_ecms_news_data_1 set newstext=replace(newstext,'原来','现在');
- python 利用 for ... else 跳出双层嵌套循环
背景 周末在写一个爬虫时,遇到这样一种场景:从搜索结果中下载指定数量的文件 例如:搜索结果中共分为10页展示,加起来一共50条数据,现在要做的是从50条数据中下载指定数量的数据 为了实现这个功能,开始 ...