最大流 && 最小费用最大流模板
模板从 这里 搬运,链接博客还有很多网络流题集题解参考。
最大流模板 ( 可处理重边 )
;
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 ...
随机推荐
- .net 部署到服务端IIS,Process调用exe程序无法运行问题解决
场景: 开发某一功能将html内容转换为pdf,采用第三方插件wkhtmltopdf.exe进行转换.在本地调试正常运行,部署到服务端后文件没有正常生成. IIS中,Process打不开cmd程序,程 ...
- 算是立flag吧~~~看明天结果了~~~
嗯...以前做ssh.应该是stratus spring hibernate. 然后现在来了一个新的需求. 要用 java,bootstrap,oracle,spring boot, jquery,m ...
- 20191110 Spring Boot官方文档学习(4.2)
4.2.外部化配置 Spring Boot使您可以外部化配置,以便可以在不同环境中使用相同的应用程序代码.您可以使用Properties文件,YAML文件,环境变量和命令行参数来外部化配置.属性值可以 ...
- 【Linux 环境搭建】ubuntu下nfs安装与配置
(1)安装 #sudo apt-get install nfs-kernel-server portmap(2)修改配置文件 修改/etc/exports,增加以下内容, /root/wksp/roo ...
- mysql5.7 修改用户密码
修改vi /etc/my.cnf,增加skip-grant-tables可以免密码登录mysql use mysql ; update user set authentication_string=P ...
- 网站私有CA证书制作
所谓的网站安全证书 是通过在客户端浏览器和Web服务器之间建立一条SSL安全通道保证了双方传递信息的安全性,而且用户可以通过服务器证书验证他所访问的网站是否真实可靠. 大体步骤: ...
- 【Luogu P2201】【JZOJ 3922】数列编辑器
题面: Description 小Z是一个爱好数学的小学生.最近,他在研究一些关于整数数列的性质. 为了方便他的研究,小Z希望实现一个叫做"Open Continuous Lines Pro ...
- T-聊天止于呵呵
(现代版)俗话说:流言止于智者,聊天止于呵呵.输入一段聊天记录,你的任务是数一数有 多少段对话“止于呵呵”,即对话的最后一句话包含单词 hehe 或者它的变形. 具体来说,我们首先提取出对话的最后一句 ...
- 洛谷 - P1522 - 牛的旅行 - Cow Tours - Floyd
https://www.luogu.org/problem/P1522 好坑啊,居然还有直径不通过新边的数据,还好不是很多. 注意一定要等Floyd跑完之后再去找连通块的直径,不然一定是INF. #i ...
- vuex实现数据共享
1.store.js结构 import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Sto ...