P2598 [ZJOI2009]狼和羊的故事

题目描述

“狼爱上羊啊爱的疯狂,谁让他们真爱了一场;狼爱上羊啊并不荒唐,他们说有爱就有方向......” \(Orez\)听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! \(Orez\)的羊狼圈可以看作一个\(n*m\)个矩阵格子,这个矩阵的边缘已经装上了篱笆。可是\(Drake\)很快发现狼再怎么也是狼,它们总是对羊垂涎三尺,那首歌只不过是一个动人的传说而已。所以\(Orez\)决定在羊狼圈中再加入一些篱笆,还是要将羊狼分开来养。 通过仔细观察,\(Orez\)发现狼和羊都有属于自己领地,若狼和羊们不能呆在自己的领地,那它们就会变得非常暴躁,不利于他们的成长。\(Orez\)想要添加篱笆的尽可能的短。当然这个篱笆首先得保证不能改变狼羊的所属领地,再就是篱笆必须修筑完整,也就是说必须修建在单位格子的边界上并且不能只修建一部分。

输入输出格式

输入格式:

文件的第一行包含两个整数\(n\)和\(m\)。接下来\(n\)行每行\(m\)个整数,1表示该格子属于狼的领地,2表示属于羊的领地,0表示该格子不是任何一只动物的领地。

输出格式:

文件中仅包含一个整数\(ans\),代表篱笆的最短长度。

说明

数据范围

10%的数据 n,m≤3

30%的数据 n,m≤20

100%的数据 n,m≤100


其实如果最小割的题做了不少以后,可以看出来是最小割。

把狼连\(S\),羊连\(T\),边权置\(inf\),表示归属关系,与种族的关系不可断裂。

在网格相邻位置的狼羊,狼连羊连单向边权值1,表示必须要断。

对于0如何处理呢?我们发现,0可以被划分到\(S\)和\(T\)任意的集合中去。换而言之,0可以跟它在网格中所接触的点随便连边,只要它需要。

这样转换到图中就是直接把0直接和周围的四个点连出去即可。

再次分析一下,连出去的边有没有可以不连的?有,比如狼连0和0连狼的边,割掉同样是代表划分到\(T\)集合,可以只连一条。

但是0和0就不行,因为0是没有归属的,一个0到另一个0和它的反向边分别被割掉,代表的意义可能就不一样了,要依据其中某一个0本来的归属来定。

总结:从原无向图建模成最小割问题,一定要注意边的方向所代表的意义


Code:(这是我一开始写的DINIC,可以感受一下到底有多慢)

#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
const int N=10002;
const int M=200010;
const int inf=0x3f3f3f3f;
const int X[5]={0,0,1,0,-1};
const int Y[5]={0,-1,0,1,0};
int head[N],to[M],edge[M],next[M],cnt=1;
void add(int u,int v,int w)
{
edge[++cnt]=w;next[cnt]=head[u];to[cnt]=v;head[u]=cnt;
}
int g[N][N],n,m,t;
int get(int i,int j)
{
return m*(i-1)+j;
}
void build()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
int id=get(i,j);
if(g[i][j]==2)
{
add(id,t,inf);
add(t,id,0);
}
else
{
if(g[i][j]==1)
{
add(0,id,inf);
add(id,0,0);
}
int v;
for(int k=1;k<=4;k++)
{
if(X[k]+j==0||X[k]+j>m||Y[k]+i==0||Y[k]+i>n)
continue;
v=get(Y[k]+i,X[k]+j);
if(g[Y[k]+i][X[k]+j]!=1)
{
add(id,v,1);
add(v,id,0);
}
}
}
}
}
void init()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&g[i][j]);
t=n*m+1;
build();
}
int dep[N];
bool bfs()
{
queue <int> q;
memset(dep,0,sizeof(dep));
dep[0]=1;
q.push(0);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];i;i=next[i])
{
int v=to[i],w=edge[i];
if(!dep[v]&&w)
{
dep[v]=dep[u]+1;
if(v==t) return 1;
q.push(v);
}
}
}
return 0;
}
int s[N],tot,pre[N],used[N];
int dfs()
{
memset(used,0,sizeof(used));
s[++tot]=0;int tmp=0;
while(tot)
{
int u=s[tot];
if(u==t)
{
int mi=inf,id;
for(int i=tot;i>1;i--)
if(mi>=edge[pre[s[i]]])
{
mi=edge[pre[s[i]]];
id=i-1;
}
tmp+=mi;
for(int i=tot;i>1;i--)
{
edge[pre[s[i]]]-=mi;
edge[pre[s[i]]^1]+=mi;
}
tot=id;
used[t]=0;
}
else
{
for(int i=head[u];i;i=next[i])
{
int v=to[i],w=edge[i];
if(w&&dep[v]==dep[u]+1&&!used[v])
{
used[v]=1;
pre[v]=i;
s[++tot]=v;
break;
}
}
if(u==s[tot]) tot--;
}
}
return tmp;
}
void work()
{
int maxflow=0;
while(bfs())
maxflow+=dfs();
printf("%d\n",maxflow);
}
int main()
{
init();
work();
return 0;
}

2018.7.1

洛谷 P2598 [ZJOI2009]狼和羊的故事 解题报告的更多相关文章

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

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

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

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

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

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

  4. 洛谷$P2598\ [ZJOI2009]$狼和羊的故事 网络流

    正解:网络流 解题报告: 传送门! 昂显然考虑最小割鸭$QwQ$,就考虑说每个土地要么属于羊要么属于狼,然后如果一条边上是栅栏一定是相邻两边所属不同. 所以考虑给所有羊向$S$连$inf$,所有狼向$ ...

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

    P2598 [ZJOI2009]狼和羊的故事 源点和所有狼连 $inf$ 的边 所有羊和汇点连 $inf$ 的边 所有点向四周连 $1$ 的边 这样所有狼和羊之间的边都被割掉了 统计最小割就好辣 #i ...

  6. P2598 [ZJOI2009]狼和羊的故事(最小割)

    P2598 [ZJOI2009]狼和羊的故事 题目描述 “狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么 ...

  7. P2598 [ZJOI2009]狼和羊的故事(最小割)

    P2598 [ZJOI2009]狼和羊的故事 说真的,要多练练网络流的题了,这么简单的网络流就看不出来... 题目要求我们要求将狼和羊分开,也就是最小割,(等等什么逻辑...头大....) 我们这样想 ...

  8. p2598 [ZJOI2009]狼和羊的故事

    传送门 分析 起点向狼连边,羊向终点连边,边权均为inf 每个点向它四联通的点连边权萎1的边 跑最小割即可 代码 #include<iostream> #include<cstdio ...

  9. 题解 P2598 【[ZJOI2009]狼和羊的故事】

    P2598 [ZJOI2009]狼和羊的故事 题目描述 "狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......" Orez听到这首歌,心想:狼 ...

随机推荐

  1. C程序员必读的 3 本书

    C程序员必读的 3 本书 原创: Martin 老师  公众号:零基础零障碍学习C语言 勿用质疑,今天来看这篇文章的朋友都是准备学好C语言的朋友,大家想学好C语言的迫切性,就好比Martin老师等着元 ...

  2. SICP读书笔记 3.4

    SICP CONCLUSION 让我们举起杯,祝福那些将他们的思想镶嵌在重重括号之间的Lisp程序员 ! 祝我能够突破层层代码,找到住在里计算机的神灵! 目录 1. 构造过程抽象 2. 构造数据抽象 ...

  3. Aria2 Linux 完整安装及使用教程

    Aria2 嘛,主要是用来离线下载,功能强大,支持 http/https 直链.ftp.电驴.磁力链接等等,且可以跨平台使用,配合网页端操作,简直是一代下载神器. 安装 Debian/Ubuntu: ...

  4. 浏览器初始页面设置及被hao123劫持解决办法

    最近在用浏览器时打开初始页面都是hao123,喵喵喜欢简单干净的页面,就去设置初始页面. 此处放置初始页面参考(并不太难): https://jingyan.baidu.com/article/11c ...

  5. Workbook对象的方法总结(二)

    (1).Worksheet 对象有 row_dimensions 和 column_dimensions 属性,控制行高和列宽. 例如: >>> sheet.row_dimensio ...

  6. 对PBFT算法的理解

    PBFT论文断断续续读了几遍,每次读或多或少都会有新的理解,结合最近的项目代码,对于共识的原理有了更清晰的认识.虽然之前写过一篇整理PBFT论文的博客,但是当时只是知道了怎么做,却不理解为什么.现在整 ...

  7. Daily Scrum 11.19 部分测试报告

    下面是我们的部分测试报告: 功能测试部分: 1Exception in thread "Thread-11" java.lang.IllegalArgumentException: ...

  8. Class 1

    “在最艰苦的时候,就是你离成功最近的时候”,让暴风雨来得更猛烈些吧. 健身教练/学员,买的那本Java Web还是那么新,显然假期偷懒了,只能一点一点的补回来了.一个假期没有打开过自己的脑洞,真心醉了 ...

  9. HDU3629(凸四边形的个数)

    HDU 3629 计算几何 题目描述:给你n个点(4~700), 问你能够成多少个不同的凸四边形. 解题报告: 暴力的话C(700,4)必然超时,发现,任何一个凹包必然是其中一点在其它3点构成的三角形 ...

  10. 注册表:DWORD

    百度百科 DWORD全称Double Word,是指注册表的键值,每个word为2个字节的长度,DWORD 双字即为4个字节,每个字节是8位,共32位. 在键值项窗口空白处单击右键,选择“新建”菜单项 ...