如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用。
第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。
接下来M行每行包含四个正整数ui、vi、wi、fi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi),单位流量的费用为fi。
输出格式:一行,包含两个整数,依次为最大流量和在最大流量情况下的最小费用。
4 5 4 3 4 2 30 2 4 3 20 3 2 3 20 1 2 1 30 9 1 3 40 5
50 280
时空限制:1000ms,128M
(BYX:最后两个点改成了1200ms)
数据规模:
对于30%的数据:N<=10,M<=10
对于70%的数据:N<=1000,M<=1000
对于100%的数据:N<=5000,M<=50000
样例说明:
如图,最优方案如下:
第一条流为4-->3,流量为20,费用为3*20=60。
第二条流为4-->2-->3,流量为20,费用为(2+1)*20=60。
第三条流为4-->2-->1-->3,流量为10,费用为(2+9+5)*10=160。
故最大流量为50,在此状况下最小费用为60+60+160=280。
故输出50 280。
首先这里给出的费用是单位流量的费用,这样最小费用就可以求出来了。
通俗的说,最小费用最大流其实就是最大流算法+Bellman-Ford算法,求最大流的同时,维护它的最短路径。
这里有几个要注意的点:
最大流的求法和原算法不变,直接加上就行了,最小费用也就可以得到是 最大流量 * 最小路径。
然后存储边的时候要把两边存在相邻(如0(0),1(1) 2(10),3(11) 等)的位置,这样就可以通过 ^1 来实现互相查询。
另外反向边的权值应为原边的相反数(走反向边相当于回溯,把原来走的边倒走回来)
最大费用直接把边去相反数即可转换为最小费用
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 5000;
const int INF = 1E9;
typedef long long LL;
typedef double DB;
inline int get(){
char c;
while((c = getchar()) < '0' || c > '9');
int cnt = c - '0';
while((c = getchar()) >= '0' && c <= '9') cnt = cnt * 10 + c - '0';
return cnt;
}
int N,M,S,T;
struct edge{
int from,to,f,w;
edge(int u,int v,int f,int w):from(u),to(v),f(f),w(w){}
};
vector e;
vector g[MAXN + 10];
int a[MAXN + 10];
int dis[MAXN + 10];
int pa[MAXN + 10];
bool est[MAXN + 10];
LL minv,maxf;
inline void mvmf(int Sat,int End){
while(1){
memset(a,0,sizeof(a));
memset(dis,127,sizeof(dis));
memset(est,false,sizeof(est));
queue q;
q.push(Sat);
dis[Sat] = 0; a[Sat] = INF; est[Sat] = true;
while(!q.empty()){
int f = q.front(); q.pop(); est[f] = false;
for(int i = 0; i < g[f].size(); i ++){
edge k = e[g[f][i]];
if(/*!a[k.to] &&*/ k.f > 0 && dis[k.from] + k.w < dis[k.to]){
a[k.to] = min(a[k.from],k.f);
dis[k.to] = dis[k.from] + k.w;
pa[k.to] = g[f][i];
if(!est[k.to]){
q.push(k.to);
est[k.to] = true;
}
}
}
}
if(!a[End]) break;
for(int i = End; i != Sat; i = e[pa[i]].from){
e[pa[i]].f -= a[End];
e[pa[i] ^ 1].f += a[End];
}
minv += (LL)dis[End] * (LL)a[End]; //
maxf += a[End];
}
return;
}
int main(){
#ifdef lwy
freopen("1.txt","r",stdin);
/* #else
freopen(".in","r",stdin);
freopen(".out","w",stdout);*/
#endif
N = get(); M = get(); S = get(); T = get();
for(int i = 1; i <= M; i ++){
int u,v,f,w;
u = get(); v = get(); f = get(); w = get();
e.push_back(edge(u,v,f,w));// u,v
e.push_back(edge(v,u,0,-w)); // v,u w -> -w
int m = e.size();
g[u].push_back(m - 2);
g[v].push_back(m - 1);
}
minv = 0;
mvmf(S,T);
printf("%d %d",maxf,minv);
return 0;
}