网络流专题

T1:

时空隧道

还是翻译一下...(CtrlC+CtrlV)...

Seal

【题目背景】 NOI2030 前夜,作为出题人的 Z 君正在颓隔膜。这个隔膜是这样的:在上古 秘境中,勇者们发现了封印古代恶魔的地方。不幸的是,这里的封印已经濒临崩 溃,恶魔们即将苏醒。勇者们决定使用魔法水晶加固封印,让恶魔们再次沉睡。

【题目描述】 封印恶魔的地方可以看作是一个 n*m 的矩形,包含了 n*m 个祭坛,并且其 中有一些祭坛已经损坏了。如果 i+j 为偶数,那么第 i 行第 j 列的祭坛只要没有损 坏,就一定会封印有一个恶魔。 其他的没有损坏的祭坛可以用来放置魔法水晶,但是一个祭坛上只能放置一 个魔法水晶,并且一个魔法水晶只能向一个与它相邻的祭坛输送魔力,从而加固 封印。 对于一个恶魔来说,如果与它相邻的两个成直角的水晶同时向它所在的祭坛 输送魔力的话,它就会被再次封印。 现在 Z 君想知道他最多可以封印多少恶魔?

【输入格式】 第一行两个整数 n,m,含义见题目描述。 接下来 n 行,每行一个长度为 m 的字符串,只包含’X’和’.’。如果第 i 行第 j 个字符为’X’,则意味着第 i 行第 j 列的祭坛已经损坏。

【输出格式】 一行一个整数表示答案。

【样例输入】

3 3

【样例输出】

2

【数据规模与约定】

对于 40%的数据,m≤10。

对于 100%的数据,1≤n,m≤50,0≤K≤n*m。

分析:

考试的时候我的想法是这样滴:

因为每个恶魔四周都有四个点可以向它连边,而我们要求的是选择上下中的一个和左右中的一个向他连边...所以我们需要把这四个点分类...

因为发现左右的点和上下的点行编号的奇偶性永远不同,所以我们把水晶点按照行编号分为两类,S向奇数行编号的点连容量为1的边,奇数行编号的点向偶数行编号的点连容量为1,然后偶数行编号的点向恶魔连容量为1的边...我觉得可对了...但是我造了了一个3*3的数据卡了自己...

3 3

X..

.XX

XXX

ans=0,但是我跑出来是1TAT...

为什么不用我说了吧...

怎么解决...我思考了好久...还是不会...然后听完正解发现我就是个智障...

我们只需要把奇数行编号的点向恶魔连边然后恶魔向偶数行编号的点连边就好了...

这就是一种解决限制的方法...受教受教...

代码:

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 //by NeighThorn
 6 #define inf 0x3f3f3f3f
 7 using namespace std;
 8 //gao shan yang zhi,jing hang xing zhi
 9
10 const int N=50+5,maxn=10000+5,maxm=2000000+5;
11
12 int n,m,S,T,cnt,hd[maxn],fl[maxm],to[maxm],nxt[maxm],pos[maxn];
13
14 int mv[4][2]={0,1,0,-1,1,0,-1,0};
15
16 char mp[N][N];
17
18 inline bool bfs(void){
19     memset(pos,-1,sizeof(pos));
20     int head=0,tail=0,q[maxn];
21     q[0]=S,pos[S]=0;
22     while(head<=tail){
23         int top=q[head++];
24         for(int i=hd[top];i!=-1;i=nxt[i])
25             if(pos[to[i]]==-1&&fl[i])
26                 pos[to[i]]=pos[top]+1,q[++tail]=to[i];
27     }
28     return pos[T]!=-1;
29 }
30
31 inline int find(int v,int f){
32     if(v==T)
33         return f;
34     int res=0,t;
35     for(int i=hd[v];i!=-1&&f>res;i=nxt[i])
36         if(pos[to[i]]==pos[v]+1&&fl[i])
37             t=find(to[i],min(f-res,fl[i])),res+=t,fl[i]-=t,fl[i^1]+=t;
38     if(!res)
39         pos[v]=-1;
40     return res;
41 }
42
43 inline int dinic(void){
44     int res=0,t;
45     while(bfs())
46         while(t=find(S,inf))
47             res+=t;
48     return res;
49 }
50
51 inline void add(int s,int x,int y){
52     fl[cnt]=s;to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
53     fl[cnt]=0;to[cnt]=x;nxt[cnt]=hd[y];hd[y]=cnt++;
54 }
55
56 signed main(void){
57     freopen("Seal.in","r",stdin);
58     freopen("Seal.out","w",stdout);
59     scanf("%d%d",&n,&m);
60     S=0,T=n*m*2+1;cnt=0;
61     memset(hd,-1,sizeof(hd));
62     for(int i=1;i<=n;i++)
63         scanf("%s",mp[i]+1);
64     for(int i=1;i<=n;i++)
65         for(int j=1;j<=m;j++){
66             if((((i+j)&1)==0)&&mp[i][j]!=‘X‘){
67                 add(1,(i-1)*m+j,(i-1)*m+j+n*m);
68                 for(int t=0;t<4;t++){
69                     int x=i+mv[t][0],y=j+mv[t][1];
70                     if(x>=1&&x<=n&&y>=1&&y<=m&&mp[i][j]!=‘X‘){
71                         if(x&1)
72                             add(1,(x-1)*m+y,(i-1)*m+j);
73                         else
74                             add(1,(i-1)*m+j+n*m,(x-1)*m+y);
75                     }
76                 }
77             }
78             else if(((i+j)&1)&&mp[i][j]!=‘X‘){
79                 if(i&1)
80                     add(1,S,(i-1)*m+j);
81                 else
82                     add(1,(i-1)*m+j,T);
83             }
84         }
85     printf("%d\n",dinic());
86     return 0;
87 }//Cap ou pas cap. Cap.

T2:

时空隧道

Repair

【题目背景】

NOI2030 的考场上,开考 5 分钟后,出题人 Z 君突然发现由于昨晚颓隔膜, 他的数据造错了。Z 君在造数据之前生成了一个网络流的可行流,但这个可行流 出了一些错误,有一些边的流量超出了容量上限,有一些点不满足流量平衡。现 在,Z 君想用最少的时间改正这些错误。

【题目描述】

给出一张 n 个点、m 条边的有向图,每条边有一个流量上限 c 和一个当前流 量 f。源点是 1,汇点是 n。你可以对每条边的 c 和 f 进行修改,但只能改成非负 整数,修改花费的时间等于改动后的数值与原来的数值之差的绝对值。请问使得 每条边的 0≤f≤c,且除源汇点以外的点流量平衡的最少用时。

【输入格式】

第一行两个整数 n,m。 接下来 m 行,每行四个整数 x,y,c,f,表示有一条从 x 到 y 的容量上限为 c, 当前流量为 f 的边。保证没有自环,可能有重边。

【输出格式】

一行一个整数表示最少时间。

【样例输入】

4 4

1 2 2 3

1 3 2 5

2 4 2 2

3 4 2 4

【样例输出】

6

【数据规模与约定】

对于 100%的数据,1≤n≤500,1≤m≤5,000,0≤c,f≤10,000。

分析:

类似于上下界网络流的做法...我们还是采用源汇补充流的做法...

定义最终流量为l,设x=f-c

No.1 f>c

  1、l>f>c

    ans=l-f+l-c=x+2l-2f

  2、f>l>c

    ans=f-l+l-c=x

  3、f>c>l

    ans=f-l=x-l+c

  我们可以看到每种情况的ans化简之后都含有x=f-c,所以我们直接在ans加上f-c,然后建边...

  需要建一条从x到y的容量为+∞费用为2的边(就是增大流量增大容量),还有从y到x的容量为f-c费用为0的边(减小流量直到符合容量),还有从y到x容量为c费用为1的边(减少流量)...(这些应该很好理解吧...)

No.2 f<=c

  和上面差不多,依旧分类讨论一下...(我懒癌晚期...就不写了...)

  然后add(y,x,f,1),add(x,y,c-f,1),add(x,y,inf,2)...

现在我们可以满足所有的边都符合要求...那么考虑点是否流量守恒...

如果in[i]>out[i]那么这个点需要流出in[i]-out[i]的流,那么就从S到i连一条容量为in[i]-out[i]的边,如果out[i]>in[i]那么这个点需要流入out[i]-in[i]的流,那么就从这个点向T连一条容量为out[i]-in[i]的边,(包括st),但是现在我们要求st不能流量守恒,所以我们要从t向s连一条容量为+∞的边,这样就把流向t的流都流回了s...

然后跑最小费用最大流就好了...

代码:

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<queue>
 6 //by NeighThorn
 7 #define inf 0x3f3f3f3f
 8 using namespace std;
 9 //nan you qiao mu,bu ke xiu si
10
11 const int maxn=100+5,maxm=10000+5;
12
13 int n,m,S,T,ans,cnt,w[maxm],hd[maxn],fl[maxm],to[maxm],nxt[maxm],pos[maxn],dif[maxn],dis[maxn],Min[maxn],vis[maxn],from[maxn];
14
15 inline bool spfa(void){
16     memset(dis,inf,sizeof(dis));
17     memset(Min,inf,sizeof(Min));
18     queue<int> q;q.push(S),vis[S]=1,dis[S]=0;
19     while(!q.empty()){
20         int top=q.front();q.pop();vis[top]=0;
21         for(int i=hd[top];i!=-1;i=nxt[i])
22             if(dis[to[i]]>dis[top]+w[i]&&fl[i]){
23                 from[to[i]]=i;
24                 dis[to[i]]=dis[top]+w[i];
25                 Min[to[i]]=min(Min[top],fl[i]);
26                 if(!vis[to[i]])
27                     vis[to[i]]=1,q.push(to[i]);
28             }
29     }
30     return dis[T]!=inf;
31 }
32
33 inline int find(void){
34     for(int i=T;i!=S;i=to[from[i]^1])
35         fl[from[i]]-=Min[T],fl[from[i]^1]+=Min[T];
36     return Min[T]*dis[T];
37 }
38
39 inline int dinic(void){
40     int res=0;
41     while(spfa())
42         res+=find();
43     return res;
44 }
45
46 inline void add(int l,int s,int x,int y){
47     w[cnt]=l;fl[cnt]=s;to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
48     w[cnt]=-l;fl[cnt]=0;to[cnt]=x;nxt[cnt]=hd[y];hd[y]=cnt++;
49 }
50
51 signed main(void){
52     // freopen("in.txt","r",stdin);
53     // freopen("out.txt","w",stdout);
54     cnt=ans=0;
55     memset(hd,-1,sizeof(hd));
56     scanf("%d%d",&n,&m);S=0,T=n+1;
57     for(int i=1,c,f,x,y;i<=m;i++){
58         scanf("%d%d%d%d",&x,&y,&c,&f);dif[x]-=f,dif[y]+=f;
59         if(f>c)
60             ans+=f-c,add(0,f-c,y,x),add(1,c,y,x),add(2,inf,x,y);
61         else
62             add(1,f,y,x),add(1,c-f,x,y),add(2,inf,x,y);
63     }
64     for(int i=1;i<=n;i++){
65         if(dif[i]>0)
66             add(0,dif[i],S,i);
67         else if(dif[i]<0)
68             add(0,-dif[i],i,T);
69     }
70     add(0,inf,n,1);printf("%d\n",ans+dinic());
71     return 0;
72 }//Cap ou pas cap. Cap.

T3:

先%ZXR...

Flow

【题目背景】

Z 君终于赶在比赛结束前修改完了他的数据,但是他不能确定自己的标程对 于新的数据能否给出正确的答案。于是他只好向你求助,希望你能帮他写一份程 序用来对拍。

【题目描述】

Z 君出的题目是这样的:给出一张 n 个点、m 条边的有向无环图,对于一条 边 e 来说,有一个容量限制 u(e)、一个单位费用 c(e)。源点是 s,汇点是 t。 定义一个流 f 是一个 s-t 流,当且仅当对于每条边 e,f(e)是一个 0~u(e)的实 数,即 0≤f(e)≤u(e),且除源汇两点外每个点的流入流量等于流出流量。 定义流 f 的流量 F(f)和费用 C(f)分别为: F(f)等于源点的流出流量减流入流量; C(f)等于每条边的流量乘以单位费用的和,即Σf(e)*c(e)。 现在定义一个函数 G(f)=C(f)2+(MaxFlow-F(f))2,其中 MaxFlow 等于 max{F(f)}, 即最大流的流量。 要求求出一个 s-t 流 f,使得 G(f)最小,以最简分数 p/q 的形式输出最小的 G(f),保证答案为有理数。

【输入格式】

第一行两个正整数 n,m。 第二行两个正整数 s,t 表示源点和汇点。 接下来 m 行,每行四个正整数 x,y,u,c,表示有一条 x 到 y 的容量上界为 u, 单位费用为 c。

【输出格式】

一行一个分数 p/q 表示最小的 G(f)。

【样例输入】

3 3

1 2

1 2 1 1

1 3 3 1

3 2 3 2

【样例输出】

10/1

【数据规模与约定】

对于 100%的数据,n≤100,m≤1000,u≤100,c≤100。 保证无重边、自环,数据存在梯度。

分析:

再%GZZ...

题解详见YOUSIKI的代码...



By NeighThorn

时间: 2025-01-04 03:50:47

网络流专题的相关文章

网络流专题练习Day2

04/17  目前做了:4题 由于目前四道都是1A感觉非常爽... BZOJ1412: [ZJOI2009]狼和羊的故事 “狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! Orez的羊狼圈可以看作一个n*m个矩阵格子,这个矩阵的边缘已经装上了篱笆.可是Drake很快发现狼再怎么也是狼,它们总是对羊垂涎三尺,那首歌只不过是一个动人的传说而已.所以Orez决定在羊狼圈中再加入一

网络流专题练习Day1

04/16 一共做了8道题 首先网络流目前自己掌握的只有最大流Dinic算法和普通的费用流算法 有空还要去学习一下SAP和ZKW费用流(flag早早立在前面以后看到都有动力... 但网络流的算法个人认为并不重要,解题的关键和思维的难点都在建图上 所以这一类的题目往往将模板一打,剩下的代码就非常短 将看起来毫无关系的题目转化成网络流做十分有趣 BZOJ3931 CQOI2015网络吞吐量 题目描述 路由是指通过计算机网络把信息从源地址传输到目的地址的活动,也是计算机网络设计中的重点和难点.网络中实

【网络流专题4】 最小点权覆盖集

Ahead 11.1.2018 例题 poj 2125 题意为选取一些点使得覆盖所有的边 仍然是最小割与割点,对于每一条边的两个点,从源点向每个点连一条删除从这个点出发的所有边的权值 即W- ,同理对每一个点向汇点连W+ 中间部分为图的边关系. 然后最大流即可 针对方案需要进行一次深搜,对于与源点连接的点,如果不能被访问到,那么一定是割去的,对于与汇点相连的如果被访问到那么一定是割去的 代码 #include <iostream> #include <cstdlib> #inclu

UVa 11082 (网络流建模) Matrix Decompressing

网络流不难写,难的建一个能解决问题的模型.. 即使我知道这是网络流专题的题目,也绝不会能想出这种解法,=_=|| 题意: 给出一个矩阵的 前i行和 以及 前i列和,然后找到一个满足要求的矩阵,而且每个元素在1~20之间. 分析: 先求出每行的元素和A'i    每列的元素和B'i 紫书上说建一个二分图,每行是一个X节点,每列代表一个Y节点. 因为流量最小是0,而题中说元素大小在1~20之间,所以我们先将每个元素都减一. 这样每行的元素和就变成了A'i-C,每列之和变为B'i-R XY之间每条边的

网络流测试-2019.3.24

网络流专题测试-2019.03.24 24号的考试了,但是一直忘了写,今天来补一补. defuze:http://hzwer.com/6009.html 不想写题面了,直接说怎么做吧. 其实这道题可以直接用最普通的费用流来做,找增广路时把spfa的比较函数改改就行了,但是我没想到. 可以对概率取对数,转成加法再做,就非常简单了. 注意:找增广路时设置一个精度,如果两条路径的差小于精度,就不进行松弛.否则可能会在几条费用极其相似的道路上反复增光导致超时. 1 # include <cstdio>

「总结」网络流

网络流专题,总结一下. 一.最大流 一个网络图的最大流量,满足网络流的各种性质的情况下. 1.蜥蜴 简单的拆点,在点之间限流即可,设有$a_i$的高度,从$S$向有蜥蜴的柱子$x$连边,边缘的柱子向$T$连边,距离小于$i,j$. $$link(S,x,1),link(i_0,i_1,a_i),link(j,T,INF),link(i,j,INF)$$ 跑最大流就可以了. 2. 二.最小割 三.最大权闭合子图 根据最小割的模型,我们建立另外一个模型,关于物品是否被选择的模型. 对于一个物品来说,

HDU 3081:Marriage Match II(二分图匹配+并查集)

http://acm.hdu.edu.cn/showproblem.php?pid=3081 题意:有n个男生n个女生,他们只有没有争吵或者女生a与男生A没有争吵,且女生b与女生a是朋友,因此女生b也可以和男生A过家家(具有传递性).给出m个关系,代表女生a和男生b没有争吵过.给出k个关系,代表女生a与女生b是好朋友.每一轮过家家之后,女生只能选择可以选择并且没选过的男生过家家,问游戏能进行几轮. 思路:因为n<=100,因此支持O(n^3)的算法,挺容易想到是一个二分图匹配的.(出现在我的网络

2016计蒜客复赛题解

3/6 这场比赛没什么高手玩啊!!两题就100+,本来是三题的,这评判系统真是*了狗了!!! ╭(╯^╰)╮. 题B 联想专卖店大促销 题意:略 题解:其实是一道简单的贪心题,看着case量还以为要推什么公式,构造一个最优策略→_→,做法就是:如果有机械键盘就优选这个,然后呢,如果u盘大于鼠标的话,那么就优先采用u盘的套餐二,否则就采用套餐一,直到不够机械键盘为止,然后就是剩下两个套餐交替的情况了. 1 /*zhen hao*/ 2 #include <bits/stdc++.h> 3 usi

2017年7月17日

今天又学了遍强连通,突然觉得好有趣啊,听别人讲了以后感觉理解更深了. 其实好多都很好理解啊,只要自己想通了基本就一下子就get到那个点了. Tarjan算法还是不难. 感觉自己补题补不动啊,自己讲的网络流专题还没怎么开始做. 就觉得建边好神奇啊???建出来很有趣的样子??? 晚上吃了木桶鱼!好好吃啊!! 肿么办,自己每天都睡不够!回去根本不想写代码! 明天肯定能早起!(●ˇ?ˇ●)今天早点睡 (? ?_?)?补题去了