bzoj 1070 [SCOI2007]修車 費用流
阿新 • • 發佈:2018-08-15
void bzoj set getch clas tchar sed pan mat
題面
題目傳送門
解法
感覺解法還是挺妙的
將每一個工人都拆成\(n\)個點,總共\(n×m\)個點
然後第\(i\)個工人的第\(j\)個點表示某輛車是在倒數第\(j\)個開始修的
然後就轉化成修車的時間對總時間的貢獻
連接\(s\)和\(n\)輛車,容量為1,費用為0,
連接\(t\)和最後的\(n×m\)個點,容量為1,費用為0
連接代表車的\(n\)個點和代表工人的\(n×m\)個點,容量為1,費用為\(k×tim_{i,j}\)
然後跑一遍費用流即可
代碼
#include <bits/stdc++.h> #define N 1010 using namespace std; template <typename node> void chkmax(node &x, node y) {x = max(x, y);} template <typename node> void chkmin(node &x, node y) {x = min(x, y);} template <typename node> void read(node &x) { x = 0; int f = 1; char c = getchar(); while (!isdigit(c)) {if (c == ‘-‘) f = -1; c = getchar();} while (isdigit(c)) x = x * 10 + c - ‘0‘, c = getchar(); x *= f; } struct Edge { int next, num, c, w; } e[N * N]; int s, t, cnt, dis[N], pre[N], las[N], used[N], tim[N][N]; void add(int x, int y, int c, int w) { e[++cnt] = (Edge) {e[x].next, y, c, w}; e[x].next = cnt; } void Add(int x, int y, int c, int w) { add(x, y, c, w), add(y, x, 0, -w); } bool spfa(int s, int t) { queue <int> q; q.push(s); for (int i = 0; i <= t; i++) dis[i] = INT_MAX, used[i] = 0; dis[s] = 0; used[s] = 1; while (!q.empty()) { int x = q.front(); used[x] = 0; q.pop(); for (int p = e[x].next; p; p = e[p].next) { int k = e[p].num, c = e[p].c, w = e[p].w; if (c && dis[k] > dis[x] + w) { dis[k] = dis[x] + w; pre[k] = x, las[k] = p; if (!used[k]) q.push(k), used[k] = 1; } } } return dis[t] != INT_MAX; } int EK(int s, int t) { int ret = 0; while (spfa(s, t)) { int fl = INT_MAX; for (int x = t; x != s; x = pre[x]) chkmin(fl, e[las[x]].c); ret += dis[t] * fl; for (int x = t; x != s; x = pre[x]) e[las[x]].c -= fl, e[las[x] ^ 1].c += fl; } return ret; } int main() { int n, m; read(n), read(m); for (int i = 1; i <= m; i++) for (int j = 1; j <= n; j++) read(tim[i][j]); s = 0, t = cnt = m + n * m + 1; if (cnt % 2 == 0) cnt++; for (int i = 1; i <= n * m; i++) Add(s, i, 1, 0); for (int i = n * m + 1; i <= n * m + m; i++) Add(i, t, 1, 0); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) for (int k = 1; k <= m; k++) Add((i - 1) * m + j, n * m + k, 1, tim[k][i] * j); cout << fixed << setprecision(2) << (double)EK(s, t) / m << "\n"; return 0; }
bzoj 1070 [SCOI2007]修車 費用流