洛谷AC传送门!

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的更多相关文章

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

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

  2. P2172 [国家集训队]部落战争 二分图最小不相交路径覆盖

    二分图最小不相交路径覆盖 #include<bits/stdc++.h> using namespace std; ; ; ; ], nxt[MAXM << ], f[MAXM ...

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

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

  4. [国家集训队]部落战争 最大流 BZOJ2150

    题目描述 lanzerb的部落在A国的上部,他们不满天寒地冻的环境,于是准备向A国的下部征战来获得更大的领土. A国是一个M*N的矩阵,其中某些地方是城镇,某些地方是高山深涧无人居住.lanzerb把 ...

  5. 洛谷P2172 [国家集训队]部落战争 题解

    题目链接:https://www.luogu.org/problemnew/show/P2172 分析: 不要被[国家集训队]的标签吓到,其实这题不是很难. 本题可以对比P4304 [TJOI2013 ...

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

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

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

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

  8. BZOJ2150部落战争——最小路径覆盖

    题目描述 lanzerb的部落在A国的上部,他们不满天寒地冻的环境,于是准备向A国的下部征战来获得更大的领土. A国是一 个M*N的矩阵,其中某些地方是城镇,某些地方是高山深涧无人居住.lanzerb ...

  9. 【最小路径覆盖】【二分图】【最大流】【Dinic】bzoj2150 部落战争

    裸的最小路径覆盖. 把每个点拆点,变成二分图. 对于可以连边的点对(i,j):i->j'(1); 对于任意一点i,若i点为'.':S->i(1),i'->T(1); 答案为所有'.' ...

随机推荐

  1. python requests 接口测试

    1.get方法请求接口 url:显而易见,就是接口的地址url啦 headers:请求头,例如:content-type = application/x-www-form-urlencoded par ...

  2. Android 10 获取已连接上的蓝牙设备的当前电量

    前言 最近的项目中有获取连接蓝牙设备电量的需求,查找了一些资料,发现谷歌在Android8.0推出了一个getBatteryLevel的api,用来获取蓝牙设备电量百分比的方法,但在我的项目中andr ...

  3. golang关键字select的三个例子, time.After模拟socket/心跳超时

    golang关键字select的三个例子, time.After模拟socket/心跳超时   例子1 select会随机选择一个可执行的case   // 这个例子主要说明select是随机选择一个 ...

  4. 自动化运维工具Ansible之Tests测验详解

    Ansible Tests 详解与使用案例 主机规划 添加用户账号 说明: 1. 运维人员使用的登录账号: 2. 所有的业务都放在 /app/ 下「yun用户的家目录」,避免业务数据乱放: 3. 该用 ...

  5. 龟兔赛跑算法 floyed判环算法

    今天写线段树写到要用到这个算法的题目,简单的学习一下. https://blog.csdn.net/javaisnotgood/article/details/89243876 https://blo ...

  6. P4016 负载平衡问题 网络流重温

    P4016 负载平衡问题 这个题目现在第二次做,感觉没有这么简单,可能是我太久没有写这种题目了,基本上都忘记了,所以我连这个是费用流都没有看出来. 有点小伤心,知道是费用流之后,我居然还拆点了. 这个 ...

  7. Spring Cloud学习 之 Spring Cloud Ribbon(负载均衡策略)

    文章目录 AbstractLoadBalancerRule: RandomRule: RoundRobinRule: RetryRule: WeightedResponseTimeRule: 定时任务 ...

  8. OpenWrt(LEDE)2020.4.29更新 UPnP+NAS+多拨+网盘+DNS优化+帕斯沃 无缝集成+软件包

    交流群:QQ 1030484865 电报:  t_homelede   固件说明 基于Lede OpenWrt R2020.4.8版本(源码截止2020.4.29)Lienol Feed及若干自行维护 ...

  9. LFU C# 实现

    周六早上  做了下力扣的LRU 题目  后面接着看了LFU 缓存  难度提高了不少 首先 先说下 这2着 的差别把 LRU :最近 最少使用算法(Least  Recently Used).LRU 是 ...

  10. Code Review 常见的5个错误模式

    原作者:Trisha Gee Code Review 的时候,每个人都会关心最佳实践,但最坏的实践有时可能会更有启示意义. Code Review是研发团队必不可少的,但并不总是正确的.这篇文章指出了 ...