题解 P2598 【[ZJOI2009]狼和羊的故事】
P2598 [ZJOI2009]狼和羊的故事
题目描述
“狼爱上羊啊爱的疯狂,谁让他们真爱了一场;狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! Orez的羊狼圈可以看作一个n*m个矩阵格子,这个矩阵的边缘已经装上了篱笆。可是Drake很快发现狼再怎么也是狼,它们总是对羊垂涎三尺,那首歌只不过是一个动人的传说而已。所以Orez决定在羊狼圈中再加入一些篱笆,还是要将羊狼分开来养。 通过仔细观察,Orez发现狼和羊都有属于自己领地,若狼和羊们不能呆在自己的领地,那它们就会变得非常暴躁,不利于他们的成长。 Orez想要添加篱笆的尽可能的短。当然这个篱笆首先得保证不能改变狼羊的所属领地,再就是篱笆必须修筑完整,也就是说必须修建在单位格子的边界上并且不能只修建一部分。
输入输出格式
输入格式:
文件的第一行包含两个整数n和m。接下来n行每行m个整数,1表示该格子属于狼的领地,2表示属于羊的领地,0表示该格子不是任何一只动物的领地。
输出格式:
文件中仅包含一个整数ans,代表篱笆的最短长度。
分析
要保证篱笆长最小而把狼和羊分开来,我们可以联想到最小割模型。一个图的最小割就是把图分为两个部分(源点及汇点不在同一部)的边权和。最小割可以用最大流算法求得。
建模
要说到网络流,重点就在于建模了,我们怎么把此网格图转换为最大流网络流呢?其实对于一个格子,我们可以把它看做与上下左右四个方向都有一条连边,而把这个格子抽象成一个点,如下图:

依据题意和最大流的经验,我们可以连边了:(我以羊的一部作为源点,所以)源点连羊,狼连汇点,若相邻的点事狼,则连一条容量为1的边(他的模型意义是:把羊和狼分开【割】需要消耗“1”)
但是对于0怎么办呢?这是本题的难点
可以思索一下,若是把0全部归为狼或者羊吧,感觉又会有更优解(事实也是这样,因为狼和羊是等价的【把狼从羊中隔离开来等价于把羊从狼中隔离开来】,所以这样单方面划分是肯定不正确的),那么怎么办呢
你可能不会,但你的最大流算法一定知道怎么做
我们这样连:源点---羊--(边A,c=1)--0--(边B, c=1)--狼---汇点
试想一下,你的篱笆的作用是分割狼和羊,0这些格子要么被划分到狼的领地,要么被划分到羊的领地,若是划分到狼那边,你的算法会割开靠近羊的那条边 A ,要是划分到羊这边,他会自动割开靠近狼的边 B 。一定不存在一种割的方式,使 A 和 B 同时被割开,因为你的算法知道,割一条就足以分开两点,不需要割第二条。
所以,放手给程序去跑吧
Code
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int RD(){
int out = 0,flag = 1;char c = getchar();
while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
return flag * out;
}
const int maxn = 100019,INF = 1e9;
int nume = 1;
int lenx,leny;
int map[190][190];
int mx[4] = {1,-1,0,0};
int my[4] = {0,0,1,-1};
int s,t,maxflow;
int head[maxn];
struct Node{
int v,dis,nxt;
}E[maxn << 2];
void add(int u,int v,int dis){
E[++nume].nxt = head[u];
E[nume].v = v;
E[nume].dis = dis;
head[u] = nume;
}
int lev[maxn];
bool bfs(){
queue<int>Q;
memset(lev,0,sizeof(lev));
Q.push(s);
lev[s] = 1;
while(!Q.empty()){
int u = Q.front();
Q.pop();
for(int i = head[u];i;i = E[i].nxt){
int v = E[i].v;
if(E[i].dis && !lev[v]){
lev[v] = lev[u] + 1;
Q.push(v);
if(v == t)return 1;
}
}
}
return 0;
}
int Dinic(int u,int flow){
if(u == t)return flow;
int rest = flow,k;
for(int i = head[u];i;i = E[i].nxt){
int v = E[i].v;
if(E[i].dis && lev[v] == lev[u] + 1 && rest){
k = Dinic(v,min(rest,E[i].dis));
if(!k)lev[v] = 0;
E[i].dis -= k;
E[i ^ 1].dis += k;
rest -= k;
}
}
return flow - rest;
}
int getindex(int x,int y){
return (x - 1) * leny + y;
}
bool judge(int x,int y){
if(x < 1 || x > lenx || y < 1 || y > leny)return 0;
return 1;
}
/*for(int i = 1;i <= lenx;i++){
for(int j = 1;j <= leny;j++){
}
}*/
void build(){
for(int i = 1;i <= lenx;i++){
for(int j = 1;j <= leny;j++){
if(map[i][j] == 2){
add(s,getindex(i,j),INF);
add(getindex(i,j),s,0);
}
else if(map[i][j] == 1){
add(getindex(i,j),t,INF);
add(t,getindex(i,j),0);
}
}
}
for(int i = 1;i <= lenx;i++){
for(int j = 1;j <= leny;j++){
if(map[i][j] == 2 || map[i][j] == 0){
for(int k = 0;k < 4;k++){
int nx = i + mx[k],ny = j + my[k];
if(!judge(nx,ny))continue;
if(map[nx][ny] == 1 || map[nx][ny] == 0){
add(getindex(i,j),getindex(nx,ny),1);
add(getindex(nx,ny),getindex(i,j),0);
}
}
}
}
}
}
int main(){
lenx = RD();leny = RD();
for(int i = 1;i <= lenx;i++){
for(int j = 1;j <= leny;j++){
map[i][j] = RD();
}
}
s = lenx * leny + 1,t = s + 1;
build();
int flow = 0;
while(bfs())while(flow = Dinic(s,INF))maxflow += flow;
printf("%d\n",maxflow);
return 0;
}
题解 P2598 【[ZJOI2009]狼和羊的故事】的更多相关文章
- P2598 [ZJOI2009]狼和羊的故事(网络流)
P2598 [ZJOI2009]狼和羊的故事 源点和所有狼连 $inf$ 的边 所有羊和汇点连 $inf$ 的边 所有点向四周连 $1$ 的边 这样所有狼和羊之间的边都被割掉了 统计最小割就好辣 #i ...
- 洛谷 P2598 [ZJOI2009]狼和羊的故事 解题报告
P2598 [ZJOI2009]狼和羊的故事 题目描述 "狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......" \(Orez\)听到这首歌, ...
- P2598 [ZJOI2009]狼和羊的故事(最小割)
P2598 [ZJOI2009]狼和羊的故事 题目描述 “狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么 ...
- P2598 [ZJOI2009]狼和羊的故事(最小割)
P2598 [ZJOI2009]狼和羊的故事 说真的,要多练练网络流的题了,这么简单的网络流就看不出来... 题目要求我们要求将狼和羊分开,也就是最小割,(等等什么逻辑...头大....) 我们这样想 ...
- 洛谷P2598 [ZJOI2009]狼和羊的故事 题解
题目链接: https://www.luogu.org/problemnew/show/P2598 分析: 我们知道此题的目的是将狼和羊分割开,很容易想到狼在S,羊在T中. 首先,我们可以在狼,羊,空 ...
- 洛谷 P2598 [ZJOI2009]狼和羊的故事
题目描述 “狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! Orez的羊狼圈 ...
- 洛谷P2598 [ZJOI2009]狼和羊的故事
题目描述 “狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! Orez的羊狼圈 ...
- p2598 [ZJOI2009]狼和羊的故事
传送门 分析 起点向狼连边,羊向终点连边,边权均为inf 每个点向它四联通的点连边权萎1的边 跑最小割即可 代码 #include<iostream> #include<cstdio ...
- 洛谷$P2598\ [ZJOI2009]$狼和羊的故事 网络流
正解:网络流 解题报告: 传送门! 昂显然考虑最小割鸭$QwQ$,就考虑说每个土地要么属于羊要么属于狼,然后如果一条边上是栅栏一定是相邻两边所属不同. 所以考虑给所有羊向$S$连$inf$,所有狼向$ ...
- 【题解】[ZJOI2009]狼和羊的故事
题目戳我 \(\text{Solution:}\) 显然思路,把所有羊看成一个源点,所有狼看成一个汇点,格子之间连容量为\(1\)的边,直接跑最小割. 技巧: 注意到篱笆不能把羊给割掉,狼同理.所以, ...
随机推荐
- 原生开发小程序 和 wepy 、 mpvue 对比
1.三者的开发文档以及介绍: 原生开发小程序文档:点此进入 wepy 开发文档:点此进入 mpvue 开发文档:点此进入 2.三者的简单对比: 以下用一张图来简单概括三者的区别: 小程序支持的是 WX ...
- PHP开发中常见的漏洞及防范
PHP开发中常见的漏洞及防范 对于PHP的漏洞,目前常见的漏洞有五种.分别是Session文件漏洞.SQL注入漏洞.脚本命令执行漏洞.全局变量漏洞和文件漏洞.这里分别对这些漏洞进行简要的介绍和防范. ...
- C# 钱数 小写 转 大写
public class Rmb { /// <summary> /// 转换人民币大小金额 /// </summary> /// <param name="n ...
- 第五周PSP作业
PSP表格: 累积进度条: 折线图: 饼状图:
- RIGHT-BICEP测试第二次程序
根据Right-BICEP单元测试的方法我对我写的第二次程序进行了测试: 测试一:测试能否控制使用乘除 测试二:测试是否能加括号 测试三:是否可以控制题目输出数量 测试四:能否控制输出方式,选择文件输 ...
- eclipse建包的一些细节
com.a :com.b 等会先在com文件夹下在 建立 a,b两个子文件夹,引用路径时 不可"*\\com.a\\*"而是"*\\com\\a\\*"这点基础 ...
- bat获取当前日期的前一天
批处理做这样的事情很麻烦,你可以用cscript来实现,比如把下面的内容保存为a.js文件:var d=new Date();d.setTime(d.getTime()-24*3600*1000);v ...
- 青岛 2016ICPC 区域现场赛题目
A. Relic Discovery B. Pocket Cube C. Pocky D. Lucky Coins E. Fibonacci F. Lambda Calculus G. Coding ...
- 78W的数据使用forall 进行批量转移;
create or replace procedure test_forall(CURRENTPAGE number ) as .--CURRENTPAGE number :=2 ; .PAGESIZ ...
- Vue 自定义指令练习
Vue.directive(id,definition)注册一个全局自定义指令,接收两个参数,指令ID以及定义对象 取值: <div v-demo="{ color: 'white', ...