【bzoj2150】部落战争 有上下界最小流
题目描述
lanzerb的部落在A国的上部,他们不满天寒地冻的环境,于是准备向A国的下部征战来获得更大的领土。 A国是一个M*N的矩阵,其中某些地方是城镇,某些地方是高山深涧无人居住。lanzerb把自己的部落分成若干支军队,他们约定: 1. 每支军队可以从任意一个城镇出发,并只能从上往向下征战,不能回头。途中只能经过城镇,不能经过高山深涧。 2. 如果某个城镇被某支军队到过,则其他军队不能再去那个城镇了。 3. 每支军队都可以在任意一个城镇停止征战。 4. 所有军队都很奇怪,他们走的方法有点像国际象棋中的马。不过马每次只能走1*2的路线,而他们只能走R*C的路线。 lanzerb的野心使得他的目标是统一全国,但是兵力的限制使得他们在配备人手时力不从心。假设他们每支军队都能顺利占领这支军队经过的所有城镇,请你帮lanzerb算算至少要多少支军队才能完成统一全国的大业。
输入
第一行包含4个整数M、N、R、C,意义见问题描述。接下来M行每行一个长度为N的字符串。如果某个字符是'.',表示这个地方是城镇;如果这个字符时'x',表示这个地方是高山深涧。
输出
输出一个整数,表示最少的军队个数。
样例输入
【样例输入一】
3 3 1 2
...
.x.
...
【样例输入二】
5 4 1 1
....
..x.
...x
....
x...
样例输出
【样例输出一】
4
【样例输出二】
5
题解
很容易看出来的有上下界最小流
将每个点拆成两个,设为xi和yi。S(代码中的b)->xi,容量为1,yi->T,容量为1,xi->yi,容量下界为1,上界为1。
若点i能够到达点j,则yi->xj,容量为1。
这个图的最小流即为答案。
再具体一些的最小流转化为最大流的方法:
S->xi,容量为1,yi->T,容量为1;若点i能够到达点j,则yi->xj,容量为1;
建立超级源汇SS和TT(代码中的s和t),SS->yi,容量为1,xi->TT,容量为1;
T->S,容量为inf。
从SS到TT跑最大流,记录T->S的边的流量(即反向边的残量)为ans1。
然后删除所有与SS或TT相连的边,删除T->S的边,从T到S跑最大流,记为ans2。
ans1-ans2即为答案。
注意往下走是行数增加而不是列数增加,不要弄混。
#include <cstdio>
#include <cstring>
#include <queue>
#define N 6000
#define M 200000
#define inf 0x7fffffff
#define pos(i , j , k) k * n * m + (i - 1) * m + j
using namespace std;
queue<int> q;
int map[60][60] , head[N] , to[M] , val[M] , next[M] , cnt = 1 , s , t , dis[N];
char str[60];
void add(int x , int y , int z)
{
to[++cnt] = y , val[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
to[++cnt] = x , val[cnt] = 0 , next[cnt] = head[y] , head[y] = cnt;
}
bool bfs()
{
int x , i;
memset(dis , 0 , sizeof(dis));
while(!q.empty()) q.pop();
dis[s] = 1 , q.push(s);
while(!q.empty())
{
x = q.front() , q.pop();
for(i = head[x] ; i ; i = next[i])
{
if(val[i] && !dis[to[i]])
{
dis[to[i]] = dis[x] + 1;
if(to[i] == t) return 1;
q.push(to[i]);
}
}
}
return 0;
}
int dinic(int x , int low)
{
if(x == t) return low;
int temp = low , i , k;
for(i = head[x] ; i ; i = next[i])
{
if(val[i] && dis[to[i]] == dis[x] + 1)
{
k = dinic(to[i] , min(temp , val[i]));
if(!k) dis[to[i]] = 0;
val[i] -= k , val[i ^ 1] += k;
if(!(temp -= k)) break;
}
}
return low - temp;
}
int main()
{
int n , m , r , c , i , j , b , e , ans = 0;
scanf("%d%d%d%d" , &n , &m , &r , &c) , b = 0 , e = 2 * n * m + 1 , s = 2 * n * m + 2 , t = 2 * n * m + 3;
add(e , b , inf);
for(i = 1 ; i <= n ; i ++ )
{
scanf("%s" , str + 1);
for(j = 1 ; j <= m ; j ++ ) map[i][j] = (str[j] == '.');
}
for(i = 1 ; i <= n ; i ++ )
{
for(j = 1 ; j <= m ; j ++ )
{
if(map[i][j])
{
add(b , pos(i , j , 0) , 1) , add(pos(i , j , 1) , e , 1) , add(s , pos(i , j , 1) , 1) , add(pos(i , j , 0) , t , 1);
if(i + r <= n && j + c <= m && map[i + r][j + c]) add(pos(i , j , 1) , pos(i + r , j + c , 0) , 1);
if(i + r <= n && j - c >= 1 && map[i + r][j - c]) add(pos(i , j , 1) , pos(i + r , j - c , 0) , 1);
if(i + c <= n && j + r <= m && map[i + c][j + r]) add(pos(i , j , 1) , pos(i + c , j + r , 0) , 1);
if(i + c <= n && j - r >= 1 && map[i + c][j - r]) add(pos(i , j , 1) , pos(i + c , j - r , 0) , 1);
}
}
}
while(bfs()) dinic(s , inf);
ans = val[3];
for(i = head[s] ; i ; i = next[i]) val[i] = val[i ^ 1] = 0;
for(i = head[t] ; i ; i = next[i]) val[i] = val[i ^ 1] = 0;
val[2] = val[3] = 0 , s = e , t = b;
while(bfs()) ans -= dinic(s , inf);
printf("%d\n" , ans);
return 0;
}
【bzoj2150】部落战争 有上下界最小流的更多相关文章
- sgu 176 Flow construction(有源汇的上下界最小流)
[题目链接] http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=11025 [模型] 有源汇点的上下界最小流.即既满足上下界又满足 ...
- BZOJ_2502_清理雪道_有源汇上下界最小流
BZOJ_2502_清理雪道_有源汇上下界最小流 Description 滑雪场坐落在FJ省西北部的若干座山上. 从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道), ...
- 【Loj117】有源汇上下界最小流(网络流)
[Loj117]有源汇上下界最小流(网络流) 题面 Loj 题解 还是模板题. #include<iostream> #include<cstdio> #include< ...
- SGU 176 Flow construction (有源有汇有上下界最小流)
题意:给定 n 个点,m 条有向边,如果有向边的标号是1的话,就表示该边的上界下界都为容量 ,如果有向边的标号为0的哈,表示该边的下界为0,上界为容量 ,现在问,从 1 到 n 的最小流是多少,并输出 ...
- loj #117. 有源汇有上下界最小流
题目链接 有源汇有上下界最小流,->上下界网络流 注意细节,边数组也要算上后加到SS,TT边. #include<cstdio> #include<algorithm> ...
- LOJ.117.[模板]有源汇有上下界最小流(Dinic)
题目链接 有源汇有上下界最小流 Sol1. 首先和无源汇网络流一样建图,求SS->TT最大流: 然后连边(T->S,[0,INF]),再求一遍SS->TT最大流,答案为新添加边的流量 ...
- BZOJ1458:士兵占领(有上下界最小流)
Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放 ...
- HDU 3157 Crazy Circuits (有源汇上下界最小流)
题意:一个电路板,上面有N个接线柱(标号1~N) 还有两个电源接线柱 + - 然后是 给出M个部件正负极的接线柱和最小电流,求一个可以让所有部件正常工作的总电流. 析:这是一个有源汇有上下界的 ...
- hdu3157有源汇上下界最小流
题意:有源汇上下界最小流裸题,主要就是输入要用字符串的问题 #include<bits/stdc++.h> #define fi first #define se second #defi ...
随机推荐
- HDU 2546 饭卡(带限制的01背包变形)
思路:有几个解法,如下 1)先拿出5块买最贵的菜,剩下的菜再进行01背包.如何证明正确性?设最贵的菜价e,次贵的菜价s,设减去5后的余额为x,会不会产生这样的情况,假设用5元买了e,余额最多能买到x- ...
- UVA 11572 Unique snowflakes (滑窗)
用set,保存当前区间出现过的数字,如果下一个数字没有出现过,加入,否则删掉左端点,直到没有重复为止 #include<bits/stdc++.h> using namespace std ...
- Connectivity
6492: Connectivity 时间限制: 1 Sec 内存限制: 128 MB提交: 118 解决: 28[提交][状态][讨论版][命题人:admin] 题目描述 There are N ...
- Lemonade Trade
4990: Lemonade Trade 时间限制: 1 Sec 内存限制: 128 MB Special Judge提交: 88 解决: 17[提交][状态][讨论版][命题人:admin] ...
- samba修改smb.conf后,不需要重启服务,就可生效
在修改完smb.conf后,不需要重启服务.在Centos7.3与Ubuntu18.04上验证都没有问题. 猜测可能的原因:samba是在客户端进行连接时,smb服务程序读取smb.conf配置文件信 ...
- 《队长说得队》【Alpha】Scrum meeting 4
项目 内容 这个作业属于哪个课程 >>2016级计算机科学与工程学院软件工程(西北师范大学) 这个作业的要求在哪里 >>实验十二 团队作业8:软件测试与ALPHA冲刺 团队名称 ...
- 理解AttributeUsage类
类定义: // 摘要: // 指定另一特性类的用法. 此类不能被继承. [Serializable] [AttributeUsage(AttributeTargets.Class, Inherited ...
- HTML5<nav>元素
HTML5中<nav>元素定义页面导航链接的部分区域,但并不是所有的链接都放到nav元素里面. 实例: <header id="pageHeader"> & ...
- JWT (JSON WEB Token)正确使用场景
https://www.jianshu.com/p/af8360b83a9f 讲真,别再使用JWT了! ThoughtWorks中国 2017.08.16 08:51* 字数 2882 阅读 7154 ...
- 笔记--Day1--python基础1
一.目录 1.Python介绍 python的创始人为吉多·范罗苏姆(Guido van Rossum),目前已经是使用频度特别高的开发语言. 主要应用领域: 云计算:云计算最火的语言,典型应用有Op ...