网络流
网络流问题的详细介绍可以看刘汝佳<<入门经典>>和<<训练指南>>相关部分。注意:下面的网络流模板里面考虑的都是有向图,如果要处理无向图,那么对于无向图的每条边,你需要再图上添加两个方向的边各一条且流量费用相同。
熟练模板并不是问题,问题是如何把实际的问题转化为网络流的问题来解决。
直接给出最大流的模板:
//最大流模板,可处理重边
//且节点编号从1到n,边编号从0到m-1
#include
#include
#include
#include
#define INF 1e9
using namespace std;
const int maxn=15+5;//之前这里只写10+5,一直TLE,真是悲剧
struct Edge
{
Edge(){}
Edge(int from,int to,int cap,int flow):from(from),to(to),cap(cap),flow(flow){}
int from,to,cap,flow;
};
struct Dinic
{
int n,m,s,t; //结点数,边数(包括反向弧),源点与汇点编号
vector edges; //边表 edges[e]和edges[e^1]互为反向弧
vector 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;
for(int i=1;i<=n;i++) G[i].clear();
edges.clear();
}
void AddEdge(int from,int to,int cap)
{
edges.push_back( Edge(from,to,cap,0) );
edges.push_back( Edge(to,from,0,0) );
m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool BFS()
{
memset(vis,0,sizeof(vis));
queue Q;//用来保存节点编号的
Q.push(s);
d[s]=0;
vis[s]=true;
while(!Q.empty())
{
int x=Q.front(); Q.pop();
for(int i=0; ie.flow)
{
vis[e.to]=true;
d[e.to] = d[x]+1;
Q.push(e.to);
}
}
}
return vis[t];
}
//a表示从s到x目前为止所有弧的最小残量
//flow表示从x到t的最小残量
int DFS(int x,int a)
{
if(x==t || a==0)return a;
int flow=0,f;//flow用来记录从x到t的最小残量
for(int& i=cur[x]; i0 )
{
e.flow +=f;
edges[G[x][i]^1].flow -=f;
flow += f;
a -= f;
if(a==0) break;
}
}
return flow;
}
int Maxflow()
{
int flow=0;
while(BFS())
{
memset(cur,0,sizeof(cur));
flow += DFS(s,INF);
}
return flow;
}
}DC;
int main()
{
int T; scanf("%d",&T);
for(int kase=1; kase<=T; ++kase)
{
int n,m;
scanf("%d%d",&n,&m);
DC.init(n,1,n);
while(m--)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
DC.AddEdge(u,v,w);
}
printf("Case %d: %d\n",kase,DC.Maxflow());
}
return 0;
}
最小费用最大流模板
#include
#include
#include
#include
#include
#define INF 1e9
using namespace std;
const int maxn=200+10;
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 edges;
vector 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();
for(int i=0;i Q;
Q.push(s);
while(!Q.empty())
{
int u=Q.front(); Q.pop();
inq[u]=false;
for(int i=0;ie.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]^1].flow -=a[t];
u = edges[p[u]].from;
}
return true;
}
//求出最小费用最大流
int Min_cost()
{
int flow=0,cost=0;
while(BellmanFord(flow,cost));
return cost;
}
}MM;
网络流应用
HDU 3549Flow Problem(最大流入门):解题报告!
POJ 1273Drainage Ditches(最大流入门):解题报告!
POJ 2391Ombrophobic Bovines(二分+floyd+最大流):解题报告!
POJ 3281Dining(最大流):解题报告!
POJ 2112Optimal Milking(二分+floyd+最大流):解题报告!
POJ 3498March of the Penguins(枚举+最大流):解题报告!
POJ 1459Power Network(最大流):解题报告!
POJ 1698Alice's Chance(最大流):解题报告!
POJ 2289Jamie's Contact Groups(二分+最大流):解题报告!
POJ 1087A Plug for UNIX(最大流):解题报告!
HDU 3081Marriage Match II(二分+并查集+最大流):解题报告!
HDU 3572Task Schedule(最大流):解题报告!
HDU 2732Leapin' Lizards(最大流):解题报告!
HDU 3605Escape(最大流+状态压缩):解题报告!
HDU 3277Marriage Match III(并查集+二分+最大流):解题报告!
HDU2883 kebab(离散化+最大流):解题报告!
HDU2485 Destroying the bus stations(最短路判定边+最大流):解题报告!
POJ2516 Minimum Cost(最小费用最大流):解题报告!
POJ2195 Going Home(费用流):解题报告!
POJ3422 Kaka's Matrix Travels(费用流):解题报告!
HDU1853 Cyclic Tour(最小费用流):解题报告!
POJ2135 Farm Tour(最小费用最大流):解题报告!
HDU1853 Cyclic Tour(最小费用流):解题报告!
HDU3435 A new Graph Game(费用流):解题报告!
HDU2686 Matrix(费用流):解题报告!
HDU3488 Tour(最小费用流:有向环覆盖):解题报告!
HDU3667 Transportation(最小费用最大流):解题报告!
HDU3315 My Brute(费用流):解题报告!