题目链接:UVa 10594 Data Flow
无向图的费用流。
无向图,则必须使用邻接表,这样才能解决反向边的问题。
加一个点0,表示为起点,设置cap[0][1]=D(题目给的流量D),cost[0][1]=0。显然到终点的最大流量不可能超过D,那么小于D的话表示不可解,等于D表示有解。
#include <iostream> #include <cstring> #include <stdio.h> #include <queue> using namespace std; const int MAX_N = 100 + 10; const int MAX_E = 5000; const int MAX_M = 5000 << 2; const long long first = 1; const long long LLINF = (first << 60); const int INF = (1 << 30); struct Edge1 { int u, v, next; long long cost; int flow, cap; }; struct Edge2 { int u, v; long long cost; }; Edge1 edge1[MAX_M]; Edge2 edge2[MAX_E]; int head[MAX_N]; long long dis[MAX_N]; int p[MAX_N]; bool vis[MAX_N]; int n, m, cnt, d; long long f, c, cap; void add(int u, int v, long long cost, int cap) { edge1[cnt].u = u; edge1[cnt].v = v; edge1[cnt].cap = cap; edge1[cnt].cost = cost; edge1[cnt].flow = 0; edge1[cnt].next = head[u]; head[u] = cnt; cnt++; edge1[cnt].u = v; edge1[cnt].v = u; edge1[cnt].cap = 0; edge1[cnt].cost = -cost; edge1[cnt].flow = 0; edge1[cnt].next = head[v]; head[v] = cnt; cnt++; } void EK() { queue <int> q; c = f = 0; while(true) { for(int i = 0;i <= n; i++) dis[i] = (i == 0 ? 0 : LLINF); memset(vis, false, sizeof(vis)); memset(p, -1, sizeof(p)); q.push(0); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for(int k = head[u]; k != -1; k = edge1[k].next) { int v = edge1[k].v; if(edge1[k].cap > edge1[k].flow && dis[v] > dis[u] + edge1[k].cost) { dis[v] = dis[u] + edge1[k].cost; p[v] = k; if(!vis[v]) { vis[v] = true; q.push(v); } } } } if(dis[n] == LLINF) break; int a = INF; for(int u = p[n]; u != -1; u = p[edge1[u].u])//这里的u是指第u条边,不再是邻接矩阵里面的顶点 a = min(a, edge1[u].cap - edge1[u].flow); for(int u = p[n]; u != -1; u = p[edge1[u].u])//增广,这里的u是指第u条边,不再是邻接矩阵里面的顶点 { edge1[u].flow += a; edge1[u^1].flow -= a;//注意看这里的亦或符号 比如u为2,亦或后就是3了,恰好第二条边的反向边就是第三条边 } c += dis[n] * a;//注意需要乘以距离 f += a; } } int main() { while(scanf("%d%d", &n, &m) != EOF) { cnt = 0; memset(head, -1, sizeof(head)); for(int i = 0; i < m; i++) scanf("%d%d%lld", &edge2[i].u, &edge2[i].v, &edge2[i].cost); scanf("%d%d", &d, &cap); add(0, 1, 0, d); for(int i = 0; i < m; i++) { add(edge2[i].u, edge2[i].v, edge2[i].cost, cap); add(edge2[i].v, edge2[i].u, edge2[i].cost, cap); } EK(); if(f == d) printf("%lld\n", c); else printf("Impossible.\n"); } return 0; }