网络流系列算法总结(bzoj 3438 1061)
网络流嘛,怎么看都是一堆逗逼题嘛,反正遇到还是都做不起嘛。。。。
网络流的模板非常简单,难点都在于建图,网络流的建图解决问题范围之广,下至A+B Problem,上至单纯形,线性规划。所以如果对于网络流的各种建图方式不熟悉,那么碰到对应的问题肯定完跪。
最大流:
这一部分确实没什么可以说的,你说他考裸的最大流?是不可能滴。考模拟增广路?至少我现在还没有遇到。
最小割:
网络流题目中最难的题目一般都是最小割,最小割建图大概有三种方式。
bzoj 3438 小A的作物
描述
小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物的种子,每种作物的种子有1个(就是可以种一棵作物)(用 1...n编号),现在,第i种作物种植在A中种植可以获得ai的收益,在B中种植可以获得bi的收益,而且,现在还有这么一种神奇的现象,就是某些作物 共同种在一块耕地中可以获得额外的收益,小M找到了规则中共有m种作物组合,第i个组合中的作物共同种在A中可以获得c1i的额外收益,共同总在B中可以 获得c2i的额外收益,所以,小M很快的算出了种植的最大收益,但是他想要考考你,你能回答他这个问题么?
这道题由于其中蕴含严格的依赖关系,所以我们可以通过最大权闭合子图来建图,这个思路想起来还是比较顺的,但是我讲的不是这个算法。
讲最小割模型一般化,设i点与S相连则X[i]=0,否则X[i]=1,边(w,v)的流量w[u][v]
我们可以得到
最小割=sigma(max(0,x[v]-x[u])*w[u][v])
另:x[i]<=x[j]可理解为max(0,x[i]-x[j])*inf
可以认为,变量取值范围为0/1的线性规划问题都能像这样转换为最小割问题。
在回到原题设Xi为作物i种在哪个田地,Yi为第i个条件是否满足。可以通过各种无脑变换出线性规划方程组,建图就行了,初次推导还是非常烦,但是相信多推几次应该会熟练一些。
当然这道题要求答案最大化,我们应该先默认加入所有的权值,在使损失最小化。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define MAXN 100100
#define MAXV 100100
#define MAXE 5100000
#define INF 0x3f3f3f3f
struct Edge
{
int val,np;
Edge *next,*neg;
}E[MAXE],*V[MAXV];
int tope=;
int sour=,sink=;
inline void addedge(int x,int y,int z)
{
// cout<<"Add edge:<"<<tope+1<<">"<<x<<" "<<y<<":"<<z<<endl;
E[++tope].np=y;
E[tope].val=z;
E[tope].next=V[x];
V[x]=&E[tope]; E[++tope].np=x;
E[tope].val=;
E[tope].next=V[y];
V[y]=&E[tope]; E[tope].neg=&E[tope-];
E[tope-].neg=&E[tope];
}
int q[MAXV],lev[MAXV];
int vis[MAXV],bfstime=;
bool bfs()
{
int head=-,tail=;
Edge *ne;
lev[sour]=;
vis[sour]=++bfstime;
q[]=sour;
while (head<tail)
{
for (ne=V[q[++head]];ne;ne=ne->next)
{
if (!ne->val || vis[ne->np]==bfstime)continue;
q[++tail]=ne->np;
vis[ne->np]=bfstime;
lev[ne->np]=lev[q[head]]+;
}
}
return vis[sink]==bfstime;
}
int dfs(int now,int maxf)
{
int ret=,t;
if (now==sink || !maxf)return maxf;
Edge* ne;
for (ne=V[now];ne;ne=ne->next)
{
if (!ne->val || lev[ne->np]!=lev[now]+)continue;
t=dfs(ne->np,min(maxf,ne->val));
ne->val-=t;
ne->neg->val+=t;
maxf-=t;
ret+=t;
//cout<<"Flow:"<<now<<"-"<<ne->np<<":"<<x<<"("<<ne->val<<")"<<endl;
}
if (!ret)lev[now]=-;
return ret;
}
int dinic()
{
int ret=;
while (bfs())
{
ret+=dfs(sour,INF);
}
return ret;
}
int va[MAXN],vb[MAXN]; int main()
{
freopen("input.txt","r",stdin);
int n,m;
int res=;
scanf("%d",&n);
for (int i=;i<=n;i++)
scanf("%d",va+i);
for (int i=;i<=n;i++)
scanf("%d",vb+i);
for (int i=;i<=n;i++)//x[i]==0?va[i]:vb[i]
{
res+=va[i];
res+=vb[i];
addedge(sour,i+,va[i]);//x[i]==1?-va[i] -> max(0,x[i]-0)*va[i];
addedge(i+,sink,vb[i]);//x[i]==0?-vb[i] -> max(0,1-x[i])*vb[i];
}
int t,x,y,z,ca,cb,p;
int ya,yb;
scanf("%d",&m);
for (int i=;i<=m;i++)
{
scanf("%d",&t);
scanf("%d%d",&ca,&cb);
res+=ca;res+=cb;
ya=i++n;
yb=i++n+m;
//ya[i]==1?-ca -> max(0,ya[i]-0)*ca
addedge(sour,ya,ca);
//yb[i]==0?-cb -> max(0,1-yb[i])*cb
addedge(yb,sink,cb);
for (int j=;j<t;j++)
{
scanf("%d",&p);
//if (x[p]==1) then ya[i]=1; -> ya[i]>=x[p] -> max(0,x[p]-ya[i])*inf
//if (x[p]==0) then yb[i]=0; -> yb[i]<=x[p] -> max(0,yb[i]-x[p])*inf
addedge(ya,+p,INF);
addedge(+p,yb,INF);
}
}
printf("%d\n",res-dinic());
}
bzoj 3438
在看另一道题:
n × m 的棋盘,要给每个点染色
若 (i, j) 为黑色,则美观度加 A i,j ;若为白色,则美观度增加 B i,j
若 (i, j) 与 (i, j + 1) 同为黑,则美观度增加 C i,j ;若同为白色,则美观度增加 D i,j
若 (i, j) 与 (i + 1, j) 同为黑,则美观度增加 E i,j ;若同为白色,则美观度增加 F i,j
求美观度的和的最大值
这道题是上面一道题的简化版。但可以通过另外的方式建图
这道题只有相邻两点间有连边,所以说我们可以将某两点间的边提出来,这是我们还不知道每条边的权值。
对于每一个最小割,都有对应的割边集合以及期望最小割的值,我们可以联立解方程解出答案。
这个方法适用面窄但非常方便。
费用流:
费用流在省选难度考点集中在流量平衡上。
bzoj 1061 志愿者招募
只要看出通过某种变换,原题变成了每个变量只出现两次,且一正一负的方程组,那么我们就可以将每个变量看做一条边,通过费用流解决。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 100000
#define MAXE MAXV*20
#define MAXV MAXN
#define INF 0x3f3f3f3f
struct Edge
{
int np,val,cost;
Edge *next,*neg;
}E[MAXE],*V[MAXV];
int sour=,sink=;
int tope=-;
void addedge(int x,int y,int z,int c)
{
// cout<<"Add:"<<x<<" "<<y<<" "<<z<<" "<<c<<endl;
E[++tope].np=y;
E[tope].val=z;
E[tope].cost=c;
E[tope].next=V[x];
V[x]=&E[tope]; E[++tope].np=x;
E[tope].val=;
E[tope].cost=-c;
E[tope].next=V[y];
V[y]=&E[tope]; V[x]->neg=V[y];
V[y]->neg=V[x];
}
int dis[MAXN];
int q[MAXN*];
int vis[MAXN],vistime=;
int prv[MAXN];
Edge *prve[MAXN];
int spfa(int now)
{
int head=-,tail=;
Edge *ne;
memset(dis,INF,sizeof(dis));
dis[now]=;
q[]=now;
vis[now]=++vistime;
while (head<tail)
{
now=q[++head];
vis[now]=;
for (ne=V[now];ne;ne=ne->next)
{
if (ne->val && dis[ne->np]>dis[now]+ne->cost)
{
dis[ne->np]=dis[now]+ne->cost;
prv[ne->np]=now;
prve[ne->np]=ne;
if (vis[ne->np]!=vistime)
q[++tail]=ne->np;
}
}
}
return dis[sink]!=INF;
}
pair<int,int> cost_flow()
{
pair<int,int> res;
while (spfa(sour))
{
int mxflow=INF;
for (int x=sink;x!=sour;x=prv[x])
mxflow=min(mxflow,prve[x]->val);
for (int x=sink;x!=sour;x=prv[x])
prve[x]->val-=mxflow,prve[x]->neg->val+=mxflow;
res.first+=mxflow;
res.second+=mxflow*dis[sink];
}
return res;
}
int a[MAXN]; int main()
{
//freopen("input.txt","r",stdin);
int n,m,x,y,z;
scanf("%d%d",&n,&m);
for (int i=;i<=n;i++)
scanf("%d",a+i);
for (int i=;i<=n+;i++)
{
addedge(+i-,+i,INF,);
}
for (int i=;i<=n+;i++)
{
if (a[i]>a[i-])
addedge(+i,sink,a[i]-a[i-],);
else
addedge(sour,+i,a[i-]-a[i],);
}
for (int i=;i<m;i++)
{
scanf("%d%d%d",&x,&y,&z);
addedge(+y+,+x,INF,z);
}
pair<int,int> res;
res=cost_flow();
printf("%d\n",res.second);
}
bzoj 1061
bzoj 1070:易到一看就是贪心的题目,但是贪心又无法解决。其实贪心和网络流(费用流)在多数情况是可以互换的。
题解传送门:http://www.cnblogs.com/mhy12345/p/4417083.html
暂且写到这儿,还有什么题目以后再补充。
网络流系列算法总结(bzoj 3438 1061)的更多相关文章
- BZOJ 3438 小M的礼物
BZOJ 3438 小M的礼物 Description 小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物的种子,每种作物的种子 有1个(就是可以种一棵作物)(用1. ...
- 挑战目标跟踪算法极限,SiamRPN系列算法解读
商汤科技智能视频团队首次开源其目标跟踪研究平台 PySOT.PySOT 包含了商汤科技 SiamRPN 系列算法,以及刚被 CVPR2019 收录为 Oral 的 SiamRPN++.此篇文章将解读目 ...
- BZOJ 3438 小M的作物 & BZOJ 1877 [SDOI2009]晨跑
我由衷地为我的朋友高兴.哈哈,yian,当你nick name破百上千时,再打“蒟蒻”就会被打的. 好的,说正事吧.请注意,这还是题解.但我发现,网络流实在是太套路了(怪不得这两年几乎销声匿迹).我们 ...
- 容斥原理算法总结(bzoj 2986 2839)
容斥原理是一个从小学就开始学习的算法.但是很多难题现在都觉得做的十分吃力. 容斥原理大概有两种表现形式,一种是按照倍数进行容斥,这个东西直接用莫比乌斯函数就可以了. #include<iostr ...
- 【网络流24题】 No.3 最小路径覆盖问题 (网络流|匈牙利算法 ->最大二分匹配)
[题意] 给定有向图 G=(V,E).设 P 是 G 的一个简单路(顶点不相交) 的集合.如果 V 中每个顶点恰好在 P 的一条路上,则称 P 是 G 的一个路径覆盖. P 中路径可以从 V 的任何一 ...
- RCNN系列算法的发展
一. RCNN系列的发展 1.1 R-CNN 根据以往进行目标检测的方法,在深度学习应用于目标检测时,同样首先尝试使用滑动窗口的想法,先对图片进行选取2000个候选区域,分别对这些区域进行提取特征以 ...
- 【BZOJ】1061: [Noi2008]志愿者招募(费用流+数学)
http://www.lydsy.com/JudgeOnline/problem.php?id=1061 好神的一题! 学会了一种建模方式: 当方程组内的任意变量都在其中两个方程出现且一正一负,可以建 ...
- 网络流Edmonds-Karp算法入门
今天自习课没事干,看书自学了一下网络流中的EK算法.(求最大流) 设s为源点,t为汇点,C为容量矩阵,F为流量矩阵,f为最大流量. 1.初始化F,f 2.用BFS在残量网络中找到一条从s到t的最短增广 ...
- POJ 1459 网络流 EK算法
题意: 2 1 1 2 (0,1)20 (1,0)10 (0)15 (1)20 2 1 1 2 表示 共有2个节点,生产能量的点1个,消耗能量的点1个, 传递能量的通道2条:(0,1)20 (1,0) ...
随机推荐
- oracle学习----特殊的连接方式
1.笛卡儿积 merge join cartesion SQL> select ename,dname from emp,dept; 已选择56行. 执行计划------------------ ...
- Java代码安全测试解决方案
Java代码安全测试解决方案: http://gdtesting.com/product.php?id=106
- Java并发——使用Condition线程间通信
线程间通信 线程之间除了同步互斥,还要考虑通信.在Java5之前我们的通信方式为:wait 和 notify.Condition的优势是支持多路等待,即可以定义多个Condition,每个condit ...
- 在AngularJS的controller外部直接获取$scope
为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/SJQ. http://www.cnblogs.com/shijiaqi1066/p/5560843.html ...
- PHP + ajax 实现异步登录验证
login.html: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http:/ ...
- 검색엔진의 크롤링과 인덱싱의 차이 (robots.txt 파일과 meta robots 태그의 차이점)
검색엔진의 크롤링과 인덱싱의 차이크롤링 제어는 robots.txt인덱싱 제어는 < meta name="robots" content="noindex& ...
- Maven 管理项目 jar出现miss
这个情况出现在包并没有下载下来就断了,这样的情况就从别人机器上copy一份完好的jar直接报错的那个根目录给覆盖就好了.
- Redis Cache 简介
Microsoft Azure Redis Cache 是基于流行的开源Redis Cache 1.Microsoft Azure Redis Cache 可分为以下几个级别: Basic – 单节点 ...
- 20151210 Jquery 学习笔记 AJAX 进阶
一.加载请求 在 Ajax 异步发送请求时,遇到网速较慢的情况,就会出现请求时间较长的问题.而超 过一定时间的请求,用户就会变得不再耐烦而关闭页面.而如果在请求期间能给用户一些提 示,比如:正在努力加 ...
- WebView支持特效,页面内跳转(转载!)
webView = (WebView) findViewById(R.id.lottery_webview); webView.getSettings().setJavaScriptEnabled(t ...