最小费用网络流
2016-08-19 17:37
155 查看
思路:
反复用spfa算法做源到汇的最短路进行增广,边权值为边上单位费用。反向边上的单位费用是负的。
直到无法增广,即为找到最小费用最大流。
成立原因:每次增广时,每增加1个流量,所增加的费用都是最小的。
因为有负权边(取消流的时候产生的),所以不能用迪杰斯特拉算法求最短路。
因为增广的时候要知道上个节点,这不难,但还要快速的知道其反向边是哪个,这个就比较麻烦
而如果用邻接矩阵的话又太占空间,所以用邻接表,方法如下:
给每条边编号,一个边和其的反向边放在一起,所以编号为i的边的反向边的编号是i^1
#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=1000+5;
const int INF=1000000000;
struct Edge{
int from,to,flow,weight;
Edge(int f,int t,int fl,int w):from(f),to(t),flow(fl),weight(w){}
};
vector<Edge> edges;
vector<vector<int> > G(maxn);
bool inq[maxn]; //判断是否在队列里
int dist[maxn];
int prev[maxn]; //记录路径
void AddEdge(int u,int v,int fl,int w)
{
edges.push_back(Edge(u,v,fl,w));
G[u].push_back(edges.size()-1); //保存该边的编号
}
bool Spfa(int s,int t)
{
memset(inq,false,sizeof(inq));
fill(dist,dist+t+2,INF);
memset(prev,-1,sizeof(prev));
queue<int> Q;
dist[s]=0;
inq[s]=true;
Q.push(s);
while(!Q.empty())
{
int u=Q.front(); Q.pop();
inq[u]=false;
for(int i=0;i<G[u].size();i++)
{
int v=edges[G[u][i]].to, w=edges[G[u][i]].weight, flow=edges[G[u][i]].flow;
if(flow>0&&dist[v]>dist[u]+w) //要在flow>0情况下
{
dist[v]=dist[u]+w;
prev[v]=G[u][i];
if(!inq[v]) Q.push(v),inq[v]=true;
}
}
}
return dist[t]!=INF;
}
int solve(int n) //输出最大流的最小代价
{
int s=0,t=n+1;
int Mindist=0; //最大流的最小代价
int MaxFlow=0; //最大流
AddEdge(s,1,2,0);
AddEdge(1,s,0,0);
AddEdge(n,t,2,0);
AddEdge(t,n,0,0);
while(Spfa(s,t)) //当存在最短路
{
int MinFlow=INF;
Mindist+=dist[t];
int v=t;
while(v!=s){ //计算途中最小流
Edge e=edges[prev[v]];
int u=e.from;
MinFlow=min(MinFlow,e.flow);
v=u;
}
MaxFlow+=MinFlow;
v=t;
while(v!=s){
int u=edges[prev[v]].from;
edges[prev[v]].flow-=MinFlow;
edges[prev[v]^1].flow+=MinFlow;
edges[prev[v]^1].weight=-edges[prev[v]].weight; //反向边的cost设为负的
v=u;
}
}
return Mindist;
}
int main()
{
int m,n,u,v,w;
while(scanf("%d%d",&n,&m)!=EOF)
{
edges.clear();
for(int i=0;i<=n+1;i++) G[i].clear();
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&u,&v,&w);
AddEdge(u,v,1,w); //i 是u->v边
AddEdge(v,u,1,w); //i^1是v->u边
}
cout<<solve(n)<<endl;
}
return 0;
}
反复用spfa算法做源到汇的最短路进行增广,边权值为边上单位费用。反向边上的单位费用是负的。
直到无法增广,即为找到最小费用最大流。
成立原因:每次增广时,每增加1个流量,所增加的费用都是最小的。
因为有负权边(取消流的时候产生的),所以不能用迪杰斯特拉算法求最短路。
因为增广的时候要知道上个节点,这不难,但还要快速的知道其反向边是哪个,这个就比较麻烦
而如果用邻接矩阵的话又太占空间,所以用邻接表,方法如下:
给每条边编号,一个边和其的反向边放在一起,所以编号为i的边的反向边的编号是i^1
#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=1000+5;
const int INF=1000000000;
struct Edge{
int from,to,flow,weight;
Edge(int f,int t,int fl,int w):from(f),to(t),flow(fl),weight(w){}
};
vector<Edge> edges;
vector<vector<int> > G(maxn);
bool inq[maxn]; //判断是否在队列里
int dist[maxn];
int prev[maxn]; //记录路径
void AddEdge(int u,int v,int fl,int w)
{
edges.push_back(Edge(u,v,fl,w));
G[u].push_back(edges.size()-1); //保存该边的编号
}
bool Spfa(int s,int t)
{
memset(inq,false,sizeof(inq));
fill(dist,dist+t+2,INF);
memset(prev,-1,sizeof(prev));
queue<int> Q;
dist[s]=0;
inq[s]=true;
Q.push(s);
while(!Q.empty())
{
int u=Q.front(); Q.pop();
inq[u]=false;
for(int i=0;i<G[u].size();i++)
{
int v=edges[G[u][i]].to, w=edges[G[u][i]].weight, flow=edges[G[u][i]].flow;
if(flow>0&&dist[v]>dist[u]+w) //要在flow>0情况下
{
dist[v]=dist[u]+w;
prev[v]=G[u][i];
if(!inq[v]) Q.push(v),inq[v]=true;
}
}
}
return dist[t]!=INF;
}
int solve(int n) //输出最大流的最小代价
{
int s=0,t=n+1;
int Mindist=0; //最大流的最小代价
int MaxFlow=0; //最大流
AddEdge(s,1,2,0);
AddEdge(1,s,0,0);
AddEdge(n,t,2,0);
AddEdge(t,n,0,0);
while(Spfa(s,t)) //当存在最短路
{
int MinFlow=INF;
Mindist+=dist[t];
int v=t;
while(v!=s){ //计算途中最小流
Edge e=edges[prev[v]];
int u=e.from;
MinFlow=min(MinFlow,e.flow);
v=u;
}
MaxFlow+=MinFlow;
v=t;
while(v!=s){
int u=edges[prev[v]].from;
edges[prev[v]].flow-=MinFlow;
edges[prev[v]^1].flow+=MinFlow;
edges[prev[v]^1].weight=-edges[prev[v]].weight; //反向边的cost设为负的
v=u;
}
}
return Mindist;
}
int main()
{
int m,n,u,v,w;
while(scanf("%d%d",&n,&m)!=EOF)
{
edges.clear();
for(int i=0;i<=n+1;i++) G[i].clear();
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&u,&v,&w);
AddEdge(u,v,1,w); //i 是u->v边
AddEdge(v,u,1,w); //i^1是v->u边
}
cout<<solve(n)<<endl;
}
return 0;
}
相关文章推荐
- poj 3068 有流量限制的最小费用网络流
- 使用dijkstra求解最小费用最大流网络
- 1834: [ZJOI2010]network 网络扩容 (最小费用最大流模板)
- 网络费用流-最小k路径覆盖
- 网络费用流-最小k路径覆盖
- POJ2135Farm Tour(最小费用最大流模板)
- USACO 3.1 Agri-Net 最短网络 (最小生成树)
- poj 2516 Minimum Cost 【最小费用最大流】【求解K种物品的最小费用,独立求解累加每个结果】
- POJ 3270 Cow Sorting(置换最小费用)
- hdu 3987 Harry Potter and the Forbidden Forest 求将s和t隔开的最少费用下的最小边数 最小割
- soj 3134: windy和水星 Stoer-Wagner算法求无向图的最小割集:一个无向连通网络,去掉一个边集可以使其变成两个连通分量则这个边集就是割集;最小割集当然就权和最小的割集
- BZOJ-3171 && 2661 循环格&&连连看 最小费用最大流
- Centos7 最小安装网络配置方法
- 最小费用网络流,不含重边
- (最小费用) POJ 2135 Farm Tour
- 洛谷P4014 分配问题【最小/大费用流】题解+AC代码
- hdu 6118 度度熊的交易计划 (最小费用最大流
- BZOJ-2324 营救皮卡丘 最小费用可行流+拆下界+Floyd预处理
- 【2017新疆网络赛】Our Journey of Dalian Ends 费用流
- bzoj 3876: [Ahoi2014]支线剧情 (无源汇最小费用可行流)[省选计划系列]