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;}

转载于:https://www.cnblogs.com/Tony-Double-Sky/p/9285535.html

题解 P2598 【[ZJOI2009]狼和羊的故事】相关推荐

  1. 洛谷P2598 [ZJOI2009]狼和羊的故事 题解

    题目链接: https://www.luogu.org/problemnew/show/P2598 分析: 我们知道此题的目的是将狼和羊分割开,很容易想到狼在S,羊在T中. 首先,我们可以在狼,羊,空 ...

  2. 洛谷 - P2598 [ZJOI2009]狼和羊的故事(最大流最小割)

    题目链接:点击查看 题目大意:给出一个 n * m 的矩阵,每个格子都有三种状态:狼.羊和空地,现在需要在相邻方格之间添加篱笆,问最少需要添加多少篱笆才能使得狼和羊分开 题目分析:最大流最小割,建图方 ...

  3. 洛谷P2598 [ZJOI2009]狼和羊的故事

    题目描述 "狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......" Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干 ...

  4. P2598 [ZJOI2009]狼和羊的故事(网络流)

    我个人的理解: 可以先对原图进行建模为下图 其左端是狼,右端为羊,中间是连接狼和羊的路 现在为了让狼吃不到样,就要隔断狼和羊之间的连接 也就是 在这里,我们需要隔断狼和羊之间的连接,也就是转化成最小割 ...

  5. [ZJOI2009]狼和羊的故事【最小割】

    题目链接 P2598 [ZJOI2009]狼和羊的故事 要让羊和狼都区别开来,需要的最小的割是多少?每只羊向四周有4个可能的方向,每只狼也是同样的,所以每个动物向周围可以跑出4个流,我们要建立栅栏,可 ...

  6. bzoj1412[ZJOI2009]狼和羊的故事

    bzoj1412[ZJOI2009]狼和羊的故事 题意: n*m网格,每个格子可能为狼.羊或空格.现在要在一些格子边界篱笆使羊狼分开,求最短篱笆.n,m≤100 题解: 最小割问题,建一个超级源和超级 ...

  7. [bzoj1934]: [ZJOI2009]狼和羊的故事

    1412: [ZJOI2009]狼和羊的故事 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 3105  Solved: 1567 [Submit][ ...

  8. BZOJ1412 ZJOI2009 狼和羊的故事 【网络流-最小割】

    BZOJ1412 ZJOI2009 狼和羊的故事 Description "狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......" Orez听 ...

  9. BZOJ 1412: [ZJOI2009]狼和羊的故事

    1412: [ZJOI2009]狼和羊的故事 >原题链接< Description "狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......& ...

最新文章

  1. Linux疑难杂症解决方案100篇(二十)-万字长文带你读懂正则表达式(建议收藏)
  2. 电脑怎么下mcjava版_游戏下载常见问题(苹果、电脑玩家下载须知)
  3. 计算机组装与维修bios设置,(完整版)计算机组装与维修模拟试题(BIOS设置的习题).docx...
  4. linux装redis环境变量,linux 怎样安装redis
  5. springboot 之Spring Web Mvc Framework
  6. exchange2003的简单安装方法
  7. red hat 查看mysql密码_Red Hat 下 MySQL root密码恢复
  8. HDU2107 Founding of HDU【序列处理+最大值】
  9. Bosh vs Comet vs Long Polling vs Polling
  10. SQL语句优化技术分析 整理他人的
  11. 遗传算法原理及其python实现
  12. 中级工程师基础SQL试题
  13. 华为ensp模拟校园网/企业网实例--中型企业无线网络的设计
  14. 千呼万唤的线粒体基因组完成图
  15. layui的layer弹出层内置方法
  16. nrf52832 comp for sdk 15.2.0
  17. 学数学,要“直觉”还是要“严谨”?
  18. Git入门、gitHub、gitee、gitLab远程库的学习和集成IDEA
  19. Linux内核的下载和解压
  20. TextPad安装环境配置

热门文章

  1. 由于html元素加载导致的问题
  2. Oracle12c异常关闭后启动PDBORCL(ORA-01033)
  3. vim选中字符复制/剪切/粘贴
  4. 【Java并发编程】:使用synchronized获取互斥锁
  5. Jmeter调试工具---HTTP Mirror Server
  6. SaaS系列介绍之十一: SaaS商业模式分析
  7. 从数学到密码学(八)
  8. Windows XP SP3支持多用户远程桌面连接
  9. python实践系列之(一)安装 python/pip/numpy/matplotlib
  10. 位运算实例(一):判断奇偶性