题目描述
如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用。
输入输出格式
输入格式:
第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。
接下来M行每行包含四个正整数ui、vi、wi、fi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi),单位流量的费用为fi。
输出格式:
一行,包含两个整数,依次为最大流量和在最大流量情况下的最小费用。
代码
#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
const int maxn=1005,maxm=5e5+5,INF=0x3f3f3f3f;
deque <int> Q;
int N,M,S,T,MF,MC;
int dis[maxn],vis[maxn];
int son[maxm],flw[maxm],cst[maxm],nxt[maxm],lnk[maxn],tot;
inline int read() {
int ret=0,f=1;char ch=getchar();
for (; !isdigit(ch); ch=getchar()) if (ch=='-') f=-f;
for (; isdigit(ch); ch=getchar()) ret=ret*10+ch-48;
return ret*f;
}
inline void add_edge(int c,int f,int y,int x) {
son[tot]=y,flw[tot]=f,cst[tot]=+c,nxt[tot]=lnk[x],lnk[x]=tot++;
son[tot]=x,flw[tot]=0,cst[tot]=-c,nxt[tot]=lnk[y],lnk[y]=tot++;
}
inline bool spfa() {
memset(vis,0,sizeof vis);
memset(dis,0x3f,sizeof dis);
dis[T]=0,Q.push_back(T);
while (!Q.empty()) {
int u=Q.front();
vis[u]=0,Q.pop_front();
for (register int k=lnk[u]; ~k; k=nxt[k])
if (flw[k^1]>0&&dis[son[k]]>dis[u]-cst[k]) {
dis[son[k]]=dis[u]-cst[k];
if (!vis[son[k]]) {
vis[son[k]]=1;
if (!Q.empty()&&dis[son[k]]<dis[Q.front()]) Q.push_front(son[k]);
else Q.push_back(son[k]);
}
}
}
vis[T]=1;
return dis[S]<INF;
}
int dfs(int x,int flow) {
vis[x]=1;
if (x==T) return flow;
int diss=0;
for (register int k=lnk[x]; ~k; k=nxt[k])
if (!vis[son[k]]&&flw[k]&&dis[son[k]]==dis[x]-cst[k]) {
int d=dfs(son[k],min(flow,flw[k]));
if (d<=0) continue;
MC+=d*cst[k],flw[k]-=d,flw[k^1]+=d;
diss+=d,flow-=d;
if (flow==0) break;
}
return diss;
}
int main() {
memset(lnk,-1,sizeof lnk);
N=read(),M=read(),S=1,T=N;
for (register int i=1; i<=M; i++) add_edge(read(),read(),read(),read());
while (spfa()) while (vis[T]) memset(vis,0,sizeof vis),MF+=dfs(S,INF);
printf("%d %d\n",MF,MC);
return 0;
}