洛谷P4003 无限之环(费用流)
神仙题啊……不看题解我可能一年都不一定做得出来……FlashHu大佬太强啦
到底是得有怎样的脑回路才能一眼看去就是费用流啊……
建好图之后套个板子就好了,那么我们着重来讨论一下怎么建图
首先,对于每一个水管的支管,有且仅有一个其他支管与他相连,那么就不会漏水了。用网络流的说法,就是要每个支管容量只能为1且必须满流
然而因为最优情况图可能会被分成好几个连通块,于是我们得强制所有相邻的格子都有流量才行(就是确保连通块不管怎么划分都能流)
那么黑白染色冷静一下……黑点连源,白点连汇
然后费用是因为旋转产生的……然后因为和四周都有连边所以要拆点
把每一个点拆成上下左右中,中间为原点,四周代表四个方向的水管。中间点连上源或汇,四周的点分别向能到达的接触点连边,容1费0
然后讨论旋转产生的费用……坐稳了……
先是直线型
比如射线指向上面,那么就让左下右的点连上面,左右点连边容1费1(转一次就行),下面的点连边容1费2(要转两次)
然后直角的
转一次会变成这样
那么就可以看做是上面的点跑到下面来了,那么上下建一条容1费1的边就好,左右同理。如果转了两次,刚好可以从上右一起流,费2,所以不用新加边了
最后第三种
如果顺时针转一次相当于左边到了下面,于是连边容1费1,同理下右连边容1费1,上下连边容1费2(因为上下转换要转两次)
然后其他都和以上一样分类讨论就行了
上代码吧,写的zkw费用流
- //minamoto
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<queue>
- #define inf 0x3f3f3f3f
- using namespace std;
- #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
- char buf[<<],*p1=buf,*p2=buf;
- inline int read(){
- #define num ch-'0'
- char ch;bool flag=;int res;
- while(!isdigit(ch=getc()))
- (ch=='-')&&(flag=true);
- for(res=num;isdigit(ch=getc());res=res*+num);
- (flag)&&(res=-res);
- #undef num
- return res;
- }
- #define UP(x) x+turn*sum
- #define RI(x) x+((turn+1)&3)*sum
- #define DO(x) x+((turn+2)&3)*sum
- #define LE(x) x+((turn+3)&3)*sum
- #define MD(x) x+(sum<<2)//上面几个用来计算对应点的数组下标,上下左右中。。。
- const int N=,M=;
- int sum,S=,T;
- int head[N],Next[M],ver[M],edge[M],cost[M],tot=;
- int dis[N],vis[N],cur[N],ans;
- int n,m,k=,totf,turn;
- inline void add(int u,int v,int e,int c,int tp){
- //tp表示点的颜色,如果是白点所有边都要反向,为了让流流向汇点
- if(tp) u^=v^=u^=v;
- ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e,cost[tot]=c;
- ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=,cost[tot]=-c;
- }
- queue<int> q;
- bool spfa(){
- memset(dis,-,sizeof(dis));
- memset(vis,,sizeof(vis));
- memcpy(cur,head,sizeof(int)*(T-S+));
- q.push(T),dis[T]=,vis[T]=;
- while(!q.empty()){
- int u=q.front();q.pop(),vis[u]=;
- for(int i=head[u];i;i=Next[i])
- if(edge[i^]){
- int v=ver[i],c=cost[i];
- if(dis[v]<||dis[v]>dis[u]-c){
- dis[v]=dis[u]-c;
- if(!vis[v]) vis[v]=,q.push(v);
- }
- }
- }
- return ~dis[S];
- }
- int dfs(int u,int limit){
- if(u==T||!limit) return limit;
- int flow=,f;vis[u]=;
- for(int &i=cur[u];i;i=Next[i]){
- int v=ver[i];
- if(dis[v]==dis[u]-cost[i]&&!vis[v]&&(f=dfs(v,min(limit,edge[i])))){
- flow+=f,limit-=f;
- edge[i]-=f,edge[i^]+=f;
- ans+=f*cost[i];
- if(!limit) break;
- }
- }
- vis[u]=;
- return flow;
- }
- int zkw(){
- //zkw费用流板子
- int flow=;
- while(spfa()) flow+=dfs(S,inf);
- return flow;
- }
- int main(){
- // freopen("testdata.in","r",stdin);
- n=read(),m=read();
- sum=n*m,T=sum*+;
- for(int i=;i<n;++i)
- for(int j=;j<m;++j,++k){
- turn=;
- int t=(i+j)&;
- t?add(S,MD(k),inf,,):add(MD(k),T,inf,,);
- if(i) add(DO(k-m),UP(k),,,t);
- if(j) add(RI(k-),LE(k),,,t);
- int op=read();
- if(op&) add(UP(k),MD(k),,,t),++totf;
- if(op&) add(RI(k),MD(k),,,t),++totf;
- if(op&) add(DO(k),MD(k),,,t),++totf;
- if(op&) add(LE(k),MD(k),,,t),++totf;
- //统计一下总流量顺便和中间点连边
- //因为每条边被记了两次,到时候要除以2
- switch(op){
- //直接把所有相同类型的一起处理掉
- case :++turn;
- case :++turn;
- case :++turn;
- case :
- add(RI(k),UP(k),,,t);
- add(DO(k),UP(k),,,t);
- add(LE(k),UP(k),,,t);
- break;
- case :++turn;
- case :++turn;
- case :++turn;
- case :
- add(DO(k),UP(k),,,t);
- add(LE(k),RI(k),,,t);
- break;
- case :++turn;
- case :++turn;
- case :++turn;
- case :
- add(DO(k),LE(k),,,t);
- add(DO(k),UP(k),,,t);
- add(DO(k),RI(k),,,t);
- break;
- }
- }
- printf("%d\n",(zkw()<<)==totf?ans:-);
- return ;
- }
洛谷P4003 无限之环(费用流)的更多相关文章
- 洛谷P4003 无限之环(infinityloop)(网络流,费用流)
洛谷题目传送门 题目 题目描述 曾经有一款流行的游戏,叫做 Infinity Loop,先来简单的介绍一下这个游戏: 游戏在一个 n ∗ m 的网格状棋盘上进行,其中有些小方格中会有水管,水管可能在格 ...
- BZOJ.5120.[清华集训2017]无限之环(费用流zkw 黑白染色)
题目链接 LOJ 洛谷 容易想到最小费用最大流分配度数. 因为水管形态固定,每个点还是要拆成4个点,分别当前格子表示向上右下左方向. 然后能比较容易地得到每种状态向其它状态转移的费用(比如原向上的可以 ...
- BZOJ5120 [2017国家集训队测试]无限之环 费用流
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ5120 题意概括 原题挺简略的. 题解 本题好难. 听了任轩笛大佬<国家队神犇>的讲课才 ...
- 洛谷.4015.运输问题(SPFA费用流)
题目链接 嗯..水题 洛谷这网络流二十四题的难度评价真神奇.. #include <queue> #include <cstdio> #include <cctype&g ...
- 洛谷P4015 运输问题(费用流)
传送门 源点向仓库连费用$0$,流量为储量的边,商店向汇点连费用$0$,流量为需求的边,然后仓库向商店连流量$inf$,费用对应的边,跑个费用流即可 //minamoto #include<io ...
- 洛谷P4014 分配问题(费用流)
传送门 可以把原图看做一个二分图,人在左边,任务在右边,求一个带权的最大和最小完美匹配 然而我并不会二分图做法,所以只好直接用费用流套进去,求一个最小费用最大流和最大费用最大流即可 //minamot ...
- 洛谷 - P4452 - 航班安排 - 费用流
https://www.luogu.org/problemnew/show/P4452 又一道看题解的费用流. 注意时间也影响节点,像题解那样建边就少很多了. #include<bits/std ...
- BZOJ 5120: [2017国家集训队测试]无限之环(费用流)
传送门 解题思路 神仙题.调了一个晚上+半个上午..这道咋看咋都不像图论的题竟然用费用流做,将行+列为奇数的点和偶数的点分开,也就是匹配问题,然后把一个点复制四份,分别代表这个点的上下左右接头,如果有 ...
- bzoj 5120 无限之环 & 洛谷 P4003 —— 费用流(多路增广SPFA)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5120 https://www.luogu.org/problemnew/show/P4003 ...
随机推荐
- deepin网络加速
0.进入控制中心里的“更新设置”,选择速度最快的镜像源(我的是阿里云)1.安装dnsmasq(命令:sudo aptitude install dnsmasq)2.以管理员权限打开gedit(命令:s ...
- the art of seo(chapter eleven)
Tracking Results and Measuring Success goal -> driver ***Why Measuring Success Is Essential to th ...
- kettle脚本定时任务不执行
问题描述:在centos机器上部署了kettle脚本,每天定时跑一次,但是并没有成功跑,手动执行命令是可以的.而且写了一个测试的shell脚本也是可以执行的. 解决方案: 将2的错误输出,/usr/l ...
- java-02 for循环,while循环
###############获取一个数字的每位数字############### #############1-100奇数和偶数和############## public class Sum { ...
- 「LOJ#10068」「一本通 3.1 练习 3」秘密的牛奶运输(次小生成树
题目描述 Farmer John 要把他的牛奶运输到各个销售点.运输过程中,可以先把牛奶运输到一些销售点,再由这些销售点分别运输到其他销售点. 运输的总距离越小,运输的成本也就越低.低成本的运输是 F ...
- ACM学习历程—Codeforces 446C DZY Loves Fibonacci Numbers(线段树 && 数论)
Description In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence ...
- 【LeetCode】039. Combination Sum
题目: Given a set of candidate numbers (C) (without duplicates) and a target number (T), find all uniq ...
- 制定一套适合自己团队的GITflow标准化工作流
Git作为分布式代码管理的“当红炸子鸡”,被越来越多团队使用.当团队多个人员在同一个Git仓库上进行代码开发,没有一套标准化流程,将会引起代码管理的混乱,上线流程的迷茫,影响工作效率.制定一套适合自己 ...
- 详解使用python crontab设置linux定时任务
熟悉linux的朋友应该知道在linux中可以使用crontab设置定时任务.可以通过命令crontab -e编写任务.当然也可以直接写配置文件设置任务. 但是有时候希望通过脚本自动设置,比如我们应用 ...
- python script
1.tab键自动补全(每次导入时要将脚本的路径加入到sys.path中) import sysimport readlineimport rlcompleterimport atexitimport ...