题目描述
输入格式
输出格式
样例
数据范围与提示
题目思路
有点像 EK+spfa
AC代码
#include<iostream> #include<queue> #include<algorithm> using namespace std; const int maxn = 5000 + 10; const int maxm = 50000 + 10; const int inf = 0x7fffffff; struct Edge{ int to, w,dist, next; //可将花费看成距离 }; Edge e[maxm * 2]; int head[maxn]; //用于静态链表 int dist[maxn]; //距离 int inq[maxn]; //是否在队列中 int flow[maxn]; int pre[maxn]; int nume[maxn]; //记录边的编号,还可以求反边 int cnt; int n, m,s,t,maxflow=0; long long mincost=0; void init(){ for (int i = 0; i <= n; i++) head[i] = -1; s = 1; t = n; cnt = 0; } void addedge(int u, int v, int w,int dist){ e[cnt].to = v; e[cnt].w = w; e[cnt].dist = dist; e[cnt].next = head[u]; head[u]= cnt++; } int spfa(){ queue<int> q; for (int i = 0; i <= n; i++) { dist[i] = inf; inq[i] = 0; } dist[s] = 0; flow[s] = inf; q.push(s); inq[s] = 1; while (!q.empty()){ int p = q.front(); q.pop();inq[p] = 0; for (int i = head[p]; ~i; i = e[i].next){ int v = e[i].to; if (e[i].w > 0 && dist[v] > dist[p] + e[i].dist){ dist[v] = dist[p] + e[i].dist; //更新最短路(花费的角度) pre[v] = p; //记录路径 nume[v] = i; //记录这个顶点的编号,i^1就是反向边 flow[v] = min(flow[p],e[i].w); //更新可行流 if (!inq[v]){ q.push(v); inq[v] = 1; } } } } return dist[t] < inf; } void MCMF(){ //mcmf主体 while (spfa()){ //如果不可增广,算法结束 int p = t; while (p != s){ e[nume[p]].w -= flow[t]; e[nume[p]^1].w += flow[t]; p = pre[p]; } maxflow += flow[t]; mincost += 1ll*flow[t] * dist[t]; } } int main() { cin >> n >> m ; int a, b, c, d; init(); for (int i = 0; i < m; i++){ cin >> a >> b >> c >> d; addedge(a, b, c, d); addedge(b, a, 0, -d); } MCMF(); cout << maxflow << ' ' << mincost << endl; return 0; }
题解效率