最大流 && 最小费用最大流模板
模板从 这里 搬运,链接博客还有很多网络流题集题解参考。
最大流模板 ( 可处理重边 )
; const int INF = 0x3f3f3f3f; struct Edge { int from,to,cap,flow; Edge(){} Edge(int from,int to,int cap,int flow):from(from),to(to),cap(cap),flow(flow){} }; struct Dinic { int n,m,s,t; //结点数,边数(包括反向弧),源点与汇点编号 vector<Edge> edges; //边表 edges[e]和edges[e^1]互为反向弧 vector<int> G[maxn]; //邻接表,G[i][j]表示结点i的第j条边在e数组中的序号 bool vis[maxn]; //BFS使用,标记一个节点是否被遍历过 int d[maxn]; //d[i]表从起点s到i点的距离(层次) int cur[maxn]; //cur[i]表当前正访问i节点的第cur[i]条弧 void init(int n,int s,int t) { this->n=n,this->s=s,this->t=t; ;i<=n;i++) G[i].clear(); edges.clear(); } void AddEdge(int from,int to,int cap) { edges.push_back( Edge() ); edges.push_back( Edge(to,,) ); m = edges.size(); G[); G[to].push_back(m-); } bool BFS() { memset(vis,,sizeof(vis)); queue<int> Q;//用来保存节点编号的 Q.push(s); d[s]=; vis[s]=true; while(!Q.empty()) { int x=Q.front(); Q.pop(); ; i<G[x].size(); i++) { Edge& e=edges[G[x][i]]; if(!vis[e.to] && e.cap>e.flow) { vis[e.to]=true; d[e.to] = d[x]+; Q.push(e.to); } } } return vis[t]; } //a表示从s到x目前为止所有弧的最小残量 //flow表示从x到t的最小残量 int DFS(int x,int a) { )return a; ,f;//flow用来记录从x到t的最小残量 for(int& i=cur[x]; i<G[x].size(); i++) { Edge& e=edges[G[x][i]]; ==d[e.to] && (f=DFS( e.to,min(a,e.cap-e.flow) ) )> ) { e.flow +=f; edges[G[x][i]^].flow -=f; flow += f; a -= f; ) break; } } ;///炸点优化 return flow; } int Maxflow() { ; while(BFS()) { memset(cur,,sizeof(cur)); flow += DFS(s,INF); } return flow; } }DC;
Dinic
#include<bits/stdc++.h> using namespace std; ; ;///边要是题目规定的两倍 const int INF = 0x3f3f3f3f; struct edge{ int to,cap,tot,rev; }; struct DINIC{ int n,m; edge w[maxm]; int fr[maxm]; int num[maxn],cur[maxn],first[maxn]; edge e[maxm]; void init(int n){ memset(cur,,sizeof(cur)); this->n=n; m=; } void AddEdge(int from,int to,int cap){ w[++m]=(edge){to,cap}; num[from]++,fr[m]=from; w[++m]=(edge){}; num[to]++,fr[m]=to; } void prepare(){ first[]=; ;i<=n;i++) first[i]=first[i-]+num[i-]; ;i<n;i++) num[i]=first[i+]-; num[n]=m; ;i<=m;i++){ e[first[fr[i]]+(cur[fr[i]]++)]=w[i]; )){ e[first[fr[i]]+cur[fr[i]]-].rev=first[w[i].to]+cur[w[i].to]-; e[first[w[i].to]+cur[w[i].to]-].rev=first[fr[i]]+cur[fr[i]]-; } } } int q[maxn]; int dist[maxn]; int t; bool bfs(int s){ ,r=; q[]=s; memset(dist,-,(n+)*); dist[s]=; while(l<=r){ int u=q[l++]; for(int i=first[u];i<=num[u];i++){ int v=e[i].to; ) || (!e[i].cap)) continue; dist[v]=dist[u]+; if (v==t) return true; q[++r]=v; } } ; } int dfs(int u,int flow){ if (u==t) return flow; ; for(int& i=cur[u];i<=num[u];i++){ int v=e[i].to; ) continue; int t=dfs(v,min(flow,e[i].cap)); if (t){ e[i].cap-=t; e[e[i].rev].tot+=t; flow-=t; ans+=t; if (!flow) return ans; } } return ans; } int MaxFlow(int s,int t){ ; this->t=t; while(bfs(s)){ do{ memcpy(cur,first,(n+)*); int flow; while(flow=dfs(s,INF)) ans+=flow; }while(bfs(s)); ;i<=m;i++) e[i].cap+=e[i].tot,e[i].tot=; } return ans; } }DC; int main(void) { int N, M, S, T; while(~scanf("%d %d %d %d", &N, &M, &S, &T)){ DC.init(N); while(M--){ int u, v, w; scanf("%d %d %d", &u, &v, &w); DC.AddEdge(u, v, w); } DC.prepare(); printf("%d", DC.MaxFlow(S, T)); } ; }
Dinic(这个快一点、点下标从1开始)
///这个是找到的别人的代码 ///我见过的最快的最大流代码了 ///但是我不知道原理,所以只能套一套这样子.... #include <bits/stdc++.h> ; const int INF = INT_MAX; struct Node { int v, f, index; Node(int v, int f, int index) : v(v), f(f), index(index) {} }; int n, m, s, t; std::vector<Node> edge[MAXN]; std::vector<int> list[MAXN], height, count, que, excess; typedef std::list<int> List; std::vector<List::iterator> iter; List dlist[MAXN]; int highest, highestActive; typedef std::vector<Node>::iterator Iterator; inline void init() { ; i<=n; i++) edge[i].clear(); } inline void addEdge(const int u, const int v, const int f) { edge[u].push_back(Node(v, f, edge[v].size())); edge[v].push_back(Node(u, , edge[u].size() - )); } inline void globalRelabel(int n, int t) { height.assign(n, n); height[t] = ; count.assign(n, ); que.clear(); que.resize(n + ); , qt = ; for (que[qt++] = t; qh < qt;) { ; for (Iterator p = edge[u].begin(); p != edge[u].end(); ++p) { ) { count[height[p->v] = h]++; que[qt++] = p->v; } } } ; i <= n; i++) { list[i].clear(); dlist[i].clear(); } ; u < n; ++u) { if (height[u] < n) { iter[u] = dlist[height[u]].insert(dlist[height[u]].begin(), u); ) list[height[u]].push_back(u); } } highest = (highestActive = height[que[qt - ]]); } inline void push(int u, Node &e) { int v = e.v; int df = std::min(excess[u], e.f); e.f -= df; edge[v][e.index].f += df; excess[u] -= df; excess[v] += df; < excess[v] && excess[v] <= df) list[height[v]].push_back(v); } inline void discharge(int n, int u) { int nh = n; for (Iterator p = edge[u].begin(); p != edge[u].end(); ++p) { ) { ) { push(u, *p); ) return; } else { nh = std::min(nh, height[p->v] + ); } } } int h = height[u]; ) { for (int i = h; i <= highest; i++) { for (List::iterator it = dlist[i].begin(); it != dlist[i].end(); ++it) { count[height[*it]]--; height[*it] = n; } dlist[i].clear(); } highest = h - ; } else { count[h]--; iter[u] = dlist[h].erase(iter[u]); height[u] = nh; if (nh == n) return; count[nh]++; iter[u] = dlist[nh].insert(dlist[nh].begin(), u); highest = std::max(highest, highestActive = nh); list[nh].push_back(u); } } inline int hlpp(int n, int s, int t) { ; highestActive = ; highest = ; height.assign(n, ); height[s] = n; iter.resize(n); ; i < n; i++) if (i != s) iter[i] = dlist[height[i]].insert(dlist[height[i]].begin(), i); count.assign(n, ); count[] = n - ; excess.assign(n, ); excess[s] = INF; excess[t] = -INF; ; i < (int)edge[s].size(); i++) push(s, edge[s][i]); globalRelabel(n, t); ;) { if (list[highestActive].empty()) { highestActive--; continue; } u = list[highestActive].back(); list[highestActive].pop_back(); discharge(n, u); // if (--res == 0) globalRelabel(res = n, t); } return excess[t] + INF; } int main() { while(~scanf("%d %d %d %d", &n, &m, &s, &t)){ init(); , u, v, f; i < m; i++) { scanf("%d %d %d", &u, &v, &f); addEdge(u, v, f); } printf(, s, t));///点是1~n范围的话,貌似要 n+1 } ; }
Highest Label Preflow Push(快到没人性)
最小费用最大流模板
点都是 0~N-1
struct Edge { int from,to,cap,flow,cost; Edge(){} Edge(int f,int t,int c,int fl,int co):from(f),to(t),cap(c),flow(fl),cost(co){} }; struct MCMF { int n,m,s,t; vector<Edge> edges; vector<int> G[maxn]; bool inq[maxn]; //是否在队列 int d[maxn]; //Bellman_ford单源最短路径 int p[maxn]; //p[i]表从s到i的最小费用路径上的最后一条弧编号 int a[maxn]; //a[i]表示从s到i的最小残量 //初始化 void init(int n,int s,int t) { this->n=n, this->s=s, this->t=t; edges.clear(); ;i<n;++i) G[i].clear(); } //添加一条有向边 void AddEdge(int from,int to,int cap,int cost) { edges.push_back(Edge(,cost)); edges.push_back(Edge(to,,,-cost)); m=edges.size(); G[); G[to].push_back(m-); } //求一次增广路 bool BellmanFord(int &flow, int &cost) { ;i<n;++i) d[i]=INF; memset(inq,,sizeof(inq)); d[s]=, a[s]=INF, inq[s]=; queue<int> Q; Q.push(s); while(!Q.empty()) { int u=Q.front(); Q.pop(); inq[u]=false; ;i<G[u].size();++i) { Edge &e=edges[G[u][i]]; if(e.cap>e.flow && d[e.to]>d[u]+e.cost) { d[e.to]= d[u]+e.cost; p[e.to]=G[u][i]; a[e.to]= min(a[u],e.cap-e.flow); if(!inq[e.to]){ Q.push(e.to); inq[e.to]=true; } } } } if(d[t]==INF) return false; flow +=a[t]; cost +=a[t]*d[t]; int u=t; while(u!=s) { edges[p[u]].flow += a[t]; edges[p[u]^].flow -=a[t]; u = edges[p[u]].from; } return true; } //求出最小费用最大流 int Min_cost() { ,cost=; while(BellmanFord(flow,cost)); return cost; } }MM;
struct Edge { int from,to,cap,flow,cost; Edge(int u,int v,int ca,int f,int co):from(u),to(v),cap(ca),flow(f),cost(co){}; }; struct MCMF { int n,m,s,t; vector<Edge> edges; vector<int> G[maxn]; int inq[maxn];//是否在队列中 int d[maxn];//距离 int p[maxn];//上一条弧 int a[maxn];//可改进量 void init(int n)//初始化 { this->n=n; ;i<=n;i++) G[i].clear(); edges.clear(); } void AddEdge(int from,int to,int cap,int cost)//加边 { edges.push_back(Edge(,cost)); edges.push_back(Edge(to,,,-cost)); int m=edges.size(); G[); G[to].push_back(m-); } bool SPFA(int s,int t,int &flow,int &cost)//寻找最小费用的增广路,使用引用同时修改原flow,cost { ;i<n;i++) d[i]=INF; memset(inq,,sizeof(inq)); d[s]=;inq[s]=;p[s]=;a[s]=INF; queue<int> Q; Q.push(s); while(!Q.empty()) { int u=Q.front(); Q.pop(); inq[u]--; ;i<G[u].size();i++) { Edge& e=edges[G[u][i]]; if(e.cap>e.flow && d[e.to]>d[u]+e.cost)//满足可增广且可变短 { d[e.to]=d[u]+e.cost; p[e.to]=G[u][i]; a[e.to]=min(a[u],e.cap-e.flow); if(!inq[e.to]) { inq[e.to]++; Q.push(e.to); } } } } if(d[t]==INF) return false;//汇点不可达则退出 flow+=a[t]; cost+=d[t]*a[t]; int u=t; while(u!=s)//更新正向边和反向边 { edges[p[u]].flow+=a[t]; edges[p[u]^].flow-=a[t]; u=edges[p[u]].from; } return true; } int MincotMaxflow(int s,int t) { ,cost=; while(SPFA(s,t,flow,cost)); return cost; } }MM;
网络流的知识可以参考《挑战程序设计竞赛Ⅱ》 or 以下链接
最大流 && 最小费用最大流模板的更多相关文章
- [模板]网络最大流 & 最小费用最大流
我的作业部落有学习资料 可学的知识点 Dinic 模板 #define rg register #define _ 10001 #define INF 2147483647 #define min(x ...
- BZOJ 1834: [ZJOI2010]network 网络扩容(最大流+最小费用最大流)
第一问直接跑最大流.然后将所有边再加一次,费用为扩容费用,容量为k,再从一个超级源点连一条容量为k,费用为0的边到原源点,从原汇点连一条同样的边到超级汇点,然 后跑最小费用最大流就OK了. ---- ...
- bzoj 1834: [ZJOI2010]network 网络扩容【最大流+最小费用最大流】
第一问直接跑最大流即可.建图的时候按照费用流建,费用为0. 对于第二问,在第一问dinic剩下的残量网络上建图,对原图的每条边(i,j),建(i,j,inf,cij),表示可以用c的花费增广这条路.然 ...
- 洛谷P2604 最大流+最小费用最大流
题目链接:https://www.luogu.org/problem/P2604 题目描述 给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用.求: 1. 在 ...
- POJ - 2516 Minimum Cost(最小费用最大流)
1.K种物品,M个供应商,N个收购商.每种物品从一个供应商运送到一个收购商有一个单位运费.每个收购商都需要K种物品中的若干.求满足所有收购商需求的前提下的最小运费. 2.K种物品拆开来,分别对每种物品 ...
- P3381 【模板】最小费用最大流
P3381 [模板]最小费用最大流 题目描述 如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用. 输入输出格式 输入格式: 第一行 ...
- Doctor NiGONiGO’s multi-core CPU(最小费用最大流模板)
题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=693 题意:有一个 k 核的处理器和 n 个工作,全部的工作都须要在一个核上处理一个单位的 ...
- 【网络流#2】hdu 1533 - 最小费用最大流模板题
最小费用最大流,即MCMF(Minimum Cost Maximum Flow)问题 嗯~第一次写费用流题... 这道就是费用流的模板题,找不到更裸的题了 建图:每个m(Man)作为源点,每个H(Ho ...
- 图论算法-最小费用最大流模板【EK;Dinic】
图论算法-最小费用最大流模板[EK;Dinic] EK模板 const int inf=1000000000; int n,m,s,t; struct node{int v,w,c;}; vector ...
随机推荐
- Babel编译:类
编译前 class Fruit{ static nutrition = "vitamin" static plant(){ console.log('种果树'); } name; ...
- 应用安全 - CMS - PHPCMS漏洞汇总
CVE-2011-0644 Date: 2011.1 类型: /flash_upload.php SQL注入 影响版本:phpCMS 2008 V2 PHPCMS PHPCMS通杀XSS 在我要报错功 ...
- Zabbix-常见问题解决
1.创建图形后字符乱码 # cd /usr/share/zabbix/fonts将Windows里面的 windows 控制面板——>字体——>如选择 “黑体”——>上传到当前目录# ...
- 第8周课程总结&实验报告6
实验六 Java异常 实验目的 理解异常的基本概念: 掌握异常处理方法及熟悉常见异常的捕获方法. 实验要求 练习捕获异常.声明异常.抛出异常的方法.熟悉try和catch子句的使用. 掌握自定义异常类 ...
- activemq高可用
这里是基于 zookeeper 选举方式实现的集群配置,服务器过半数才可提供服务,所以是2n+1台这里以三台为例. 只有master节点能提供服务,slave节点无法提供服务,只有当master节点挂 ...
- mysql,oracle,sql server数据库默认的端口号,端口号可以为负数吗?以及常用协议所对应的缺省端口号
mysql,oracle,sql server数据库默认的端口号? mysql:3306 Oracle:1521 sql server:1433 端口号可以为负吗? 不可以,端口号都有范围的,0~65 ...
- 什么是CPC,CPA,CVR,CTR,ROI
合格的网络营销人员都应该熟悉下面的常见英文缩写,这些都是我们必须知道的名词解释:CVR (Click Value Rate): 转化率,衡量CPA广告效果的指标CTR (Click Through R ...
- 通过runtime对类别进行属性的扩展
category使用 objc_setAssociatedObject/objc_getAssociatedObject 实现添加属性 属性 其实就是 get/set 方法. 我们可以使用 objc ...
- Spring基础03——Spring IOC和DI概述
1.什么是IOC与DI IOC(Inversion of Control):其思想是反转资源获取方向,传统的资源查找方式要求组件想容器发起请求查找资源,作为回应,容器适时的返回资源,而应用了IOC之后 ...
- 基于Kintex Ultrasacle的万兆网络光纤 PCIe加速卡416 光纤PCIe卡
基于Kintex Ultrasacle的万兆网络光纤 PCIe加速卡 一.产品概述 本卡为企业级别板卡,可用于数据中心,安全领域数据采集处理.标准PCI Express全高板,适用于普通服务器.工作站 ...