最大流最小割——bzoj1001狼抓兔子,洛谷P2598
前置知识
平面图
平面图就是平面上任意边都不相交的图。(自己瞎画的不算XD)
对偶图
比如说这个图,我们发现平面图肯定会把平面分成不同的区域(感觉像拓扑图),并把这些区域当做每个点(不被包围的区域独自成点,如本图4*),给相邻的区域连上边,就转化成了一个对偶图(图中红色)
割
网络流的图中有两个点:原点和汇点。割就是删去的一些边使原点和汇点无法连接(不太严谨)
看题!bzoj1001
既然有了原点和汇点,那么就不能简单的把外部看做一个点了,我们把外部分成两个点——超级原点和超级汇点!
然后像上面一样建边,求对偶图的最短路就行了!!!
你问我如何判断对偶图的点之间割了哪些边?
emmm这就是它恶心的地方了——建图并不容易。不过,它给边的方式还是有点人性的。
- #include<iostream>
- #include<cstdio>
- #include<algorithm>
- #include<cctype>
- #include<cstring>
- #include<utility>
- #include<queue>
- #include<functional>
- #include<vector>
- using namespace std;
- inline int read()
- {
- int x=0,w=0;char c=getchar();
- while(!isdigit(c))w|=c=='-',c=getchar();
- while(isdigit(c) )x=(x<<3)+(x<<1)+(c^48),c=getchar();
- return w?-x:x;
- }
- const int maxn=3000000;
- typedef pair<int,int> pii;
- int n,m,node[1210][1210][2];
- int ecnt,t[maxn<<1],nxt[maxn<<1],head[maxn<<1],val[maxn<<1];
- inline void addedge(int from,int to,int dis)
- {
- t[++ecnt]=to;nxt[ecnt]=head[from];head[from]=ecnt;val[ecnt]=dis;
- t[++ecnt]=from;nxt[ecnt]=head[to];head[to]=ecnt;val[ecnt]=dis;
- }
- int dis[maxn];
- bool vis[maxn];
- inline void dijkstra(int start,int end)
- {
- memset(dis,0x3f3f3f3f,sizeof dis);
- priority_queue<pii,vector<pii >,greater<pii > > q;
- q.push(make_pair(0,start)),dis[start]=0;
- while(!q.empty())
- {
- int u=q.top().second;q.pop();
- if(vis[u])continue;
- vis[u]=1;
- for(int i=head[u];i;i=nxt[i])
- {
- int v=t[i],w=val[i];
- if(dis[v]>=dis[u]+w)
- {
- dis[v]=dis[u]+w;
- q.push(make_pair(dis[v],v));
- }
- }
- }
- }
- int main()
- {
- int v=1;
- n=read()-1,m=read()-1;
- for(int i=1;i<=n;i++)
- for(int j=1;j<=m;j++)
- for(int k=0;k<2;k++)
- node[i][j][k]=v++;
- int start=v++,end=v;
- for(int j=1;j<=m;j++)addedge(start,node[1][j][0],read());
- for(int i=1;i<=n-1;i++)
- for(int j=1;j<=m;j++)
- addedge(node[i][j][1],node[i+1][j][0],read());
- for(int j=1;j<=m;j++)addedge(end,node[n][j][1],read());
- /*横行*/
- for(int i=1;i<=n;i++)
- for(int j=1;j<=m+1;j++)
- if(j==1)addedge(end,node[i][j][1],read());
- else if(j==m+1)addedge(start,node[i][j-1][0],read());
- else addedge(node[i][j-1][0],node[i][j][1],read());
- /*纵行*/
- for(int i=1;i<=n;i++)
- for(int j=1;j<=m;j++)
- addedge(node[i][j][0],node[i][j][1],read());
- /*斜行*/
- dijkstra(start,end);
- printf("%d\n",dis[end]);
- return 0;
- }
好了,以上只是针对bzoj1001的问题的解法。实际上,这个问题还有一些通用的解法(只不过出题人不想让大家用加强了数据)
不过上一道题我们也可以用下面的方式求出网络的最小割。
不过我们换一题XD
(反正狼就是nb)
通过读题,我们发现,这个orez想圈养狼真是了不起(姜戎都不敢这么干)
最大流最小割定理:网络的最大流等于最小割
证明也比较简单(但我不会严谨的),感性理解一下,最大流一定有一些边是满的,我们把这些边割了它就流不成了。对于其他的边,要么不是必经之路,要么边权不比同一条流上的最大流的边小,所以~~得证~~
那么这道题的话其他前辈已经讲得很好了,即求法就是
1. 将所有狼连到原点,边权INF
2. 将所有羊连到汇点,边权INF
3. 将所有点的四周加边,边权为1
这是一个对偶图的思想,相当于组成了一个网络,在这个网络中,只要点与点之间有边相连就相当于之间没有栅栏,所以一开始是全部连接的。我们要做的,就是砌栅栏把一些边断掉,使狼和羊分离。因为所有狼和所有羊都连在原点和汇点,这就相当于求最小割了。
(不知道讲清楚没有)
前面两个大家应该都清楚,边权INF相当于没有影响只是把所有狼/羊连在一起罢了。第三步就是连边:因为修一个栅栏需要1,所以边权为1,简直和对偶图一模一样(本来就是一个思想)
同样的,这里的难度就在于建边,建完求最大流就行了。
注意数组的大小。
- #include<iostream>
- #include<cstdio>
- #include<algorithm>
- #include<cstring>
- #include<cctype>
- #include<utility>
- #include<queue>
- using namespace std;
- inline int read()
- {
- int w=0,x=0;char c=getchar();
- while(!isdigit(c))w|=c=='-',c=getchar();
- while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
- return w?-x:x;
- }
- namespace star
- {
- const int maxn=100005,INF=0x3f3f3f3f;
- int n,m;
- int mapp[105][105];
- int ecnt=1,head[maxn],t[maxn<<1],nxt[maxn<<1],val[maxn<<1];
- inline void addedge(int from,int to, int dis)
- {
- t[++ecnt]=to;val[ecnt]=dis;nxt[ecnt]=head[from];head[from]=ecnt;
- t[++ecnt]=from;val[ecnt]=0;nxt[ecnt]=head[to];head[to]=ecnt;
- }
- int fx[]={0,1,0,-1},fy[]={1,0,-1,0};
- int cnt;
- int dep[maxn],start,end,cur[maxn];
- inline bool BFS()
- {
- queue<int> q;
- for(int i=1;i<=cnt;i++)dep[i]=-1,cur[i]=head[i];
- dep[start]=0;
- q.push(start);
- while(!q.empty())
- {
- int u=q.front();q.pop();
- for(int i=head[u];i;i=nxt[i])
- if(val[i] and dep[t[i]]==-1)
- dep[t[i]]=dep[u]+1,q.push(t[i]);
- }
- if(dep[end]==-1)return 0;
- return 1;
- }
- int DFS(int x,int flow)
- {
- if(x==end)return flow;
- int used=0;
- for(int i=cur[x];i;i=nxt[i])
- {
- cur[x]=i;
- int u=t[i];
- if(val[i] and dep[u]==dep[x]+1)
- {
- int w=DFS(u,min(val[i],flow-used));
- used+=w;
- val[i]-=w;
- val[i^1]+=w;
- if(used==flow)return flow;
- }
- }
- if(!used)dep[x]=-1;
- return used;
- }
- inline void build()
- {
- n=read(),m=read();
- cnt=0;
- for(int i=1;i<=n;i++)
- for(int j=1;j<=m;j++)
- mapp[i][j]=++cnt;
- start=++cnt,end=++cnt;
- for(int zp,i=1;i<=n;i++)
- for(int j=1;j<=m;j++)
- if((zp=read())==1)addedge(start,mapp[i][j],INF);
- else if(zp==2)addedge(mapp[i][j],end,INF);
- for(int i=1;i<=n;i++)
- for(int j=1;j<=m;j++)
- for(int k=0;k<4;k++)
- {
- int xx=i+fx[k],yy=j+fy[k];
- if(xx<1 or xx>n or yy<1 or yy>m)continue;
- addedge(mapp[i][j],mapp[xx][yy],1);
- }
- }
- inline void work()
- {
- build();
- int ans=0;
- while(BFS())ans+=DFS(start,INF);
- printf("%d\n",ans);
- }
- }
- int main()
- {
- star::work();
- return 0;
- }
最大流最小割——bzoj1001狼抓兔子,洛谷P2598的更多相关文章
- bzoj1001狼抓兔子 对偶图优化
bzoj1001狼抓兔子 对偶图优化 链接 https://www.lydsy.com/JudgeOnline/problem.php?id=1001 思路 菜鸡总是要填坑的! 很明显让你求网格图的最 ...
- 【bzoj1001】【最短路】【对偶图】【最大流转最小割】狼抓兔子题解
[BZOJ1001]狼抓兔子 1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 18872 Solved ...
- BZOJ-1001 狼抓兔子 (最小割-最大流)平面图转对偶图+SPFA
1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec Memory Limit: 162 MB Submit: 14686 Solved: 3513 [Submit][ ...
- BZOJ1001:狼抓兔子(最小割最大流+vector模板)
1001: [BeiJing2006]狼抓兔子 Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨, ...
- bzoj1001狼抓兔子
1001: [BeiJing2006]狼抓兔子 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的, 而且现在的兔子还比较笨,它们只有两个窝,现在你 ...
- BZOJ1001 狼抓兔子 平面图转对偶图 最小割
现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: 左上角点为 ...
- BZOJ1001 狼抓兔子(裸网络流)
Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的, 而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一 ...
- 【建图+最短路】Bzoj1001 狼抓兔子
Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个 ...
- [日常摸鱼]bzoj1001狼抓兔子-最大流最小割
题意就是求最小割- 然后我们有这么一个定理(最大流-最小割定理 ): 任何一个网络图的最小割中边的容量之和等于图的最大流. (下面直接简称为最大流和最小割) 证明: 如果最大流>最小割,那把这些 ...
随机推荐
- 太神奇了!GIF的合成与提取这么好玩
今天辰哥教大家一个Python有趣好玩的小功能:将多张图片转为GIF,同时也可以将一个GIF动图提取出里面的图片 在开始之前,先来一个动图开头(预览) 01.图片转GIF动图 1.准备工作 在开始合并 ...
- 「题解」300iq Contest 2 B Bitwise Xor
本文将同步发布于: 洛谷博客: csdn: 博客园: 简书. 题目 题目链接:gym102331B. 题意概述 给你一个长度为 \(n\) 的序列 \(a_i\),求一个最长的子序列满足所有子序列中的 ...
- 四、SSL虚拟证书
沿用练习三,配置基于加密网站的虚拟主机,实现以下目标: 域名为www.c.com 该站点通过https访问 通过私钥.证书对该站点所有数据加密 4.2 方案 源码安装Nginx时必须使用--with- ...
- WebClient (史上最全)
疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 面试必备 + 面试必备 [博客园总入口 ] 疯狂创客圈 经典图书 : <Sprin ...
- css基本内容笔记(学习整理)
一.css简介 1.什么是css 层叠样式表. 层叠:层层叠加,若果有冲突应用优先级高,不冲突的部分共同作用 样式表:就是css属性样式的集合: 2.作用 a.修饰html,使得html样式更好看 b ...
- git stash回退
目录 1.起因 2. 问题出现 3.修复 4. 注意 1.起因 这个问题要从今天刚遇到的事儿说起,昨晚代码出了个乌龙事件,本来正在dev分支进行新功能的开发,但是测试出现的问题是在release 分支 ...
- 可编程网络DataPath 及XDP
目录 可编程网络DataPath XDP 的基本架构 XDP 的软件要求 XDP 的硬件要求 XDP 的工作流程及使用 XDP 的工作模式 XDP 的工作流程 Hello World XDP 的应用 ...
- 聊聊 Feign 的实现原理
What is Feign? Feign 是⼀个 HTTP 请求的轻量级客户端框架.通过 接口 + 注解的方式发起 HTTP 请求调用,面向接口编程,而不是像 Java 中通过封装 HTTP 请求报文 ...
- Linux云计算-01_介绍以及Linux操作系统安装
1 学习目的 兴趣爱好 技能提升 找到满意的工作 2 什么是云计算 云计算(cloud computing)是分布式计算的一种,指的是通过网络"云"将巨大的数据计算处理程序分解成无 ...
- web自动化页面元素不能键盘输入
一.背景 web自动化中存在一部分元素属性是readonly属性,导致我们在使用自动化代码的时候无法使用sendkeys()方法传入数据,以12306网站选择出发日期为例,见下图 二.json语句处理 ...