[luoguP2053] [SCOI2007]修车(最小费用最大流)
网络流的建图真的好难!
将一个点拆分成多个点的思想还需要加强。
代码和题解中的图略不一样。
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #define N 1000001 using namespace std; int n, m, cnt, s, t; int head[N], to[N], nex[N], val[N], cost[N], dis[N], pre[N], path[N]; bool vis[N]; double tim; inline int read() { int x = 0, f = 1; char ch = getchar(); for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1; for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0'; return x * f; } inline void add(int x, int y, int z, int v) { to[cnt] = y; val[cnt] = z; cost[cnt] = v; nex[cnt] = head[x]; head[x] = cnt++; } inline bool spfa() { int i, u, v; queue <int> q; memset(vis, 0, sizeof(vis)); memset(pre, -1, sizeof(pre)); memset(dis, 127, sizeof(dis)); q.push(s); dis[s] = 0; while(!q.empty()) { u = q.front(); vis[u] = 0; q.pop(); for(i = head[u]; ~i; i = nex[i]) { v = to[i]; if(val[i] && dis[v] > dis[u] + cost[i]) { dis[v] = dis[u] + cost[i]; pre[v] = u; path[v] = i; if(!vis[v]) { q.push(v); vis[v] = 1; } } } } return pre[t] != -1; } int main() { int i, j, k, x, f; m = read(); n = read(); s = 0, t = n + n * m + 1; memset(head, -1, sizeof(head)); for(i = 1; i <= n; i++) for(j = 1; j <= m; j++) { x = read(); for(k = 1; k <= n; k++) { add((k - 1) * m + j, i + n * m, 1, k * x); add(i + n * m, (k - 1) * m + j, 0, -k * x); } add(s, j + (i - 1) * m, 1, 0); add(j + (i - 1) * m, s, 0, 0); } for(i = 1; i <= n; i++) { add(i + n * m, t, 1, 0); add(t, i + n * m, 0, 0); } while(spfa()) { f = 1e9; for(i = t; i != s; i = pre[i]) f = min(f, val[path[i]]); tim += dis[t]; for(i = t; i != s; i = pre[i]) { val[path[i]] -= f; val[path[i] ^ 1] += f; } } printf("%.2lf\n", double(tim / n)); return 0; }