bzoj 5120 [2017国家集训队测试]无限之环——网络流
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5120
旋转的话相当于去掉一个插头、新增一个插头,所以在这两个插头之间连边并带上费用即可。
网格图可以黑白染色,转化为相邻格子间插头的匹配问题。
注意:
1.黑白染色不是移动一格就 fx = ! fx ;每换一行,开头位置的颜色应该和上一行的开头不一样!不然有偶数列的话自己原来写的那个染色就崩了;
2. L 形的判断不是 d&(d>>1) 判断是否有两个相邻的1,如果是第一个位置和最后一个位置是1的话(9)就判断不出来了!可以判断 d != 5 && d != 10 ;
3.对于无解的判断,比较好的是判断插头个数的是不是流量的两倍。
然后就能很慢地 A 了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=,K=,M=K<<,INF=N;//<<4:*6 for trans *2 for between
int n,m,t,bh[K][K],hd[N],xnt=,to[M],nxt[M],cap[M],w[M],bin[];//=1!
int dis[N],pre[N],info[N],ans,val,flow; bool ins[N];
queue<int> q;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
int Mn(int a,int b){return a<b?a:b;}
void upd(int &x){x>=?x-=:;}
void add(int x,int y,int z)
{
if(!x||y==t)val++;//
to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;cap[xnt]=;w[xnt]=z;
to[++xnt]=x;nxt[xnt]=hd[y];hd[y]=xnt;cap[xnt]=;w[xnt]=-z;
}
void init()
{
int bin[];
bin[]=;for(int i=;i<;i++)bin[i]=bin[i-]<<;
bool Fx=,fx=;
for(int i=;i<=n;i++,Fx=!Fx)/////Fx!!!!!
for(int j=,fx=Fx;j<=m;j++,fx=!fx)
{
int d=rdn(),ct=; if(!fx){for(int k=;k<;k++)if(d&bin[k])ct++,add(,k+bh[i][j],);}
else {for(int k=;k<;k++)if(d&bin[k])ct++,add(k+bh[i][j],t,);}
if(ct==||ct==)///ct==1:not a chain but 1,1,2
{
int x;//caution for ct=1|3 the diff
if(ct==) {for(int k=;k<;k++)if(d&bin[k]){x=k;break;}}
else {for(int k=;k<;k++)if(!(d&bin[k])){x=k;break;}}
int y=x^,cr=x+bh[i][j];
for(int k=;k<;k++)
if(k!=x)(fx^(ct==))?add(k+bh[i][j],cr,+(k==y)):add(cr,k+bh[i][j],+(k==y));
}
// else if(ct==2&&(d&(d>>1)))//L
else if(ct==&&(d!=&&d!=))/////caution 9!!!
{
for(int k=;k<;k++)
if(d&bin[k])fx?add((k^)+bh[i][j],k+bh[i][j],):add(k+bh[i][j],(k^)+bh[i][j],);
}
if(!fx)
{
if(i>)add(bh[i][j],+bh[i-][j],);
if(j<m)add(+bh[i][j],+bh[i][j+],);
if(i<n)add(+bh[i][j],bh[i+][j],);
if(j>)add(+bh[i][j],+bh[i][j-],);
}
}
}
bool spfa()
{
memset(dis,0x3f,sizeof dis);dis[]=;
info[]=INF;info[t]=; q.push();ins[]=;
while(q.size())
{
int k=q.front();q.pop();ins[k]=;
for(int i=hd[k],v;i;i=nxt[i])
if(cap[i]&&dis[v=to[i]]>dis[k]+w[i])
{
dis[v]=dis[k]+w[i];
pre[v]=i;info[v]=Mn(info[k],cap[i]);
if(!ins[v])q.push(v),ins[v]=;
}
}
return info[t];
}
void ek()
{
int s=info[t]; flow+=s; ans+=dis[t]*s;//dis[t]!
for(int i=pre[t];i;i=pre[to[i^]])
{cap[i]-=s;cap[i^]+=s;}
}
int main()
{
n=rdn();m=rdn();t=;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++,t+=)bh[i][j]=t;
init(); if(val&){puts("-1");return ;}//
while(spfa())ek(); printf("%d\n",flow<<==val?ans:-);///
return ;
}
还学习了多路增广SPFA算法。大概适用于边权变化范围很小的那种吧。
因为边权相近,所以期望做一次SPFA之后能不仅更新出一条路,还能更多地更新,因为算出来的 dis[ ] 可能对很多条路都适用。
所以就在SPFA之后按照 dis[ ] 来 dfs ,找找所有合法的路径。在这道题上真的能快好多。
注意 dfs 要打 vis 标记,走过的就不再走了。因为网络里可能有环,这个又是按 dis 来走的,所以比如有很多0权边的话,就可能死循环。dinic 没有这个问题是因为它是按 dfn 来走的,dfn 弄出来的一定是 DAG 。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=,K=,M=K<<,INF=N;//<<4:*6 for trans *2 for between
int n,m,t,bh[K][K],hd[N],xnt=,cur[N],to[M],nxt[M],cap[M],w[M],bin[];//=1!
int dis[N],pre[N],info[N],ans,val,flow; bool ins[N];
queue<int> q;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
int Mn(int a,int b){return a<b?a:b;}
void upd(int &x){x>=?x-=:;}
void add(int x,int y,int z)
{
if(!x||y==t)val++;//
to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;cap[xnt]=;w[xnt]=z;
to[++xnt]=x;nxt[xnt]=hd[y];hd[y]=xnt;cap[xnt]=;w[xnt]=-z;
}
void init()
{
int bin[];
bin[]=;for(int i=;i<;i++)bin[i]=bin[i-]<<;
bool Fx=,fx=;
for(int i=;i<=n;i++,Fx=!Fx)/////Fx!!!!!
for(int j=,fx=Fx;j<=m;j++,fx=!fx)
{
int d=rdn(),ct=; if(!fx){for(int k=;k<;k++)if(d&bin[k])ct++,add(,k+bh[i][j],);}
else {for(int k=;k<;k++)if(d&bin[k])ct++,add(k+bh[i][j],t,);}
if(ct==||ct==)///ct==1:not a chain but 1,1,2
{
int x;//caution for ct=1|3 the diff
if(ct==) {for(int k=;k<;k++)if(d&bin[k]){x=k;break;}}
else {for(int k=;k<;k++)if(!(d&bin[k])){x=k;break;}}
int y=x^,cr=x+bh[i][j];
for(int k=;k<;k++)
if(k!=x)(fx^(ct==))?add(k+bh[i][j],cr,+(k==y)):add(cr,k+bh[i][j],+(k==y));
}
// else if(ct==2&&(d&(d>>1)))//L
else if(ct==&&(d!=&&d!=))/////caution 9!!!
{
for(int k=;k<;k++)
if(d&bin[k])fx?add((k^)+bh[i][j],k+bh[i][j],):add(k+bh[i][j],(k^)+bh[i][j],);
}
if(!fx)
{
if(i>)add(bh[i][j],+bh[i-][j],);
if(j<m)add(+bh[i][j],+bh[i][j+],);
if(i<n)add(+bh[i][j],bh[i+][j],);
if(j>)add(+bh[i][j],+bh[i][j-],);
}
}
}
bool spfa()
{
memset(ins,,sizeof ins);
memset(dis,0x3f,sizeof dis);dis[]=;
info[]=INF;info[t]=; q.push();ins[]=;
while(q.size())
{
int k=q.front();q.pop();ins[k]=;
for(int i=hd[k],v;i;i=nxt[i])
if(cap[i]&&dis[v=to[i]]>dis[k]+w[i])
{
dis[v]=dis[k]+w[i];
pre[v]=i;info[v]=Mn(info[k],cap[i]);
if(!ins[v])q.push(v),ins[v]=;
}
}
return info[t];
}
int dfs(int cr)//for cr!=0 flow must be 1
{
if(cr==t)return ; ins[cr]=;
for(int& i=cur[cr],v,tmp;i;i=nxt[i])
if(!ins[v=to[i]]&&cap[i]&&dis[v=to[i]]==dis[cr]+w[i])
if(tmp=dfs(v)){ans+=w[i];cap[i]--;cap[i^]++;return ;}
return ;
}
void MCMF()
{
int tmp;
while(spfa())
{
memcpy(cur,hd,sizeof hd);
while(tmp=dfs())flow+=tmp;
}
}
int main()
{
n=rdn();m=rdn();t=;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++,t+=)bh[i][j]=t;
init(); if(val&){puts("-1");return ;}//
MCMF(); printf("%d\n",flow<<==val?ans:-);///
return ;
}
bzoj 5120 [2017国家集训队测试]无限之环——网络流的更多相关文章
- bzoj 5120: [2017国家集训队测试]无限之环【最小费用最大流】
玄妙的建图-- 这种平衡度数的题按套路是先黑白染色然后分别连ST点,相邻格子连黑向白连费用1流量0的边,然后考虑费用怎么表示 把一个点拆成五个,上下左右中,中间点黑白染色连ST, 对于连S的点,中点连 ...
- BZOJ 5120: [2017国家集训队测试]无限之环(费用流)
传送门 解题思路 神仙题.调了一个晚上+半个上午..这道咋看咋都不像图论的题竟然用费用流做,将行+列为奇数的点和偶数的点分开,也就是匹配问题,然后把一个点复制四份,分别代表这个点的上下左右接头,如果有 ...
- BZOJ5120 [2017国家集训队测试]无限之环 费用流
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ5120 题意概括 原题挺简略的. 题解 本题好难. 听了任轩笛大佬<国家队神犇>的讲课才 ...
- [BZOJ5120] [2017国家集训队测试]无限之环
Description 曾经有一款流行的游戏,叫做InfinityLoop,先来简单的介绍一下这个游戏: 游戏在一个n×m的网格状棋盘上进行,其中有些小方格中会有水管,水管可能在方格某些方向的边界的中 ...
- BZOJ 2039 [2009国家集训队]employ人员雇佣 网络流
链接 BZOJ 2039 题解 这题建图好神,自己瞎搞了半天,最后不得不求教了企鹅学长的博客,,,,发现建图太神了!! s向每个人连sum(e[i][x]) 的边,每个人向T连a[i]的边.两两人之间 ...
- BZOJ_2622_[2012国家集训队测试]深入虎穴_最短路
BZOJ_2622_[2012国家集训队测试]深入虎穴_最短路 Description 虎是中国传统文化中一个独特的意象.我们既会把老虎的形象用到喜庆的节日装饰画上,也可能把它视作一种邪恶的可怕的动物 ...
- 【BZOJ2622】[2012国家集训队测试]深入虎穴 次短路
[BZOJ2622][2012国家集训队测试]深入虎穴 Description 虎是中国传统文化中一个独特的意象.我们既会把老虎的形象用到喜庆的节日装饰画上,也可能把它视作一种邪恶的可怕的动物,例如“ ...
- 2017国家集训队作业Atcoder题目试做
2017国家集训队作业Atcoder题目试做 虽然远没有达到这个水平,但是据说Atcoder思维难度大,代码难度小,适合我这种不会打字的选手,所以试着做一做 不知道能做几题啊 在完全自己做出来的题前面 ...
- 2017国家集训队作业[agc016b]Color Hats
2017国家集训队作业[agc016b]Color Hats 题意: 有\(N\)个人,每个人有一顶帽子.帽子有不同的颜色.现在,每个人都告诉你,他看到的所有其它人的帽子共有多少种颜色,问有没有符合所 ...
随机推荐
- 【51nod-1278】相离的圆(二分)
思路 做法就是先把圆的直径化成线段,然后将线段的起点从小到大排序,以第i条线段为例,找i+1~n条中这样一条线段,满足是第一条且起点比第i条的终点要大(即满足相离),那么包括这条线段之后的线段也满足和 ...
- 三、dbms_pipe(类似UNIX系统的管道)
1.概述 说明:Oracle管道类似UNIX系统的管道,但不采用OS机制实现,管道信息被缓存到SGA中,当关闭例程时会丢失管道信息,建立公用管道所有数据库用户都可访问,私有管道只能由建立这访问.作用: ...
- 报错:Type mismatch: cannot convert from Object to Car
问题描述: 一个非常简单的spring项目,用静态工厂方法配置bean实例.项目的目录结构如下: 代码如下: Car.java package com.tt.spring.beans.factory; ...
- Jenkins分享
2016-02-26 小马哥 程序员之路 PPT下载地址:http://pan.baidu.com/s/1i4pw6oP Jenkins 是一个开源软件项目,旨在提供一个开放易用的软件平台,使 ...
- Git远程操作详解(转)
转自:http://www.ruanyifeng.com/blog/2014/06/git_remote.html Git远程操作详解 Git是目前最流行的版本管理系统,学会Git几乎成了开发者的 ...
- c# 多线程调用窗体上的控件 示例
private delegate void InvokeCallback(string msg); private void SetCountValue(string s) { if (this.fo ...
- js的事件循环机制和任务队列
上篇讲异步的时候,提到了同步队列和异步队列的说法,其实只是一种形象的称呼,分别代表主线程中的任务和任务队列中的任务,那么此篇我们就来详细探讨这两者. 一.来张图感受一下 如果看完觉得一脸懵逼,请继续往 ...
- Content-type与json对象/字符串杂谈
这几天在对接项目另一个乙方的下行接口,因为最近一直用php开发,所以当那边接口文档上规定了接口传参类型的 时候,瞬间搞混了,但是这次的出错也让我对http的数据传输有了新的认知. 1.http的数据传 ...
- redis事务浅析
事务可以简单理解为:把多件事当做一件事情处理,要么一起成功,要么一起失败.在Spring中可以配置一个事务管理器,然后在要进行事务处理的方法上添加@Transactional注解就可以了. 对于red ...
- webpack 实现自动刷新,复制文件,实现开发环境和发布环境
webpack例子:https://github.com/Aquarius1993/webpackDemo 安装: webpack , webpack-dev-server 1.如何在使用webpac ...