[BZOJ 1070][SCOI2007]修车
转载请注明出处:http://danihao123.is-programmer.com/
啊啊啊我为什么要去颓费用流啊……
这个题可以保证每个人的车最后都会被修,所以说也就是让你最小化总等待时间辣!
直接考虑给一个技术人员建时间轴是麻烦而不可取的。我们考虑一点,对于每一个技术人员,若总共修了\(t\)辆车,那么第\(i\)个来找他修车的人会影响后面人的等待时间,换言之我们可以认为第\(i\)个来修车的人给答案做出了\(c\cdot (t - i + 1)\)(这里用\(c\)表示他自己的修车时间,注意他也会影响他自己)的贡献,似乎可以苟最小费用最大流呢。
但问题在于我们并不能提前知道\(t\)是多少,并且这样的话费用不是递增的,一个人可能会优先考虑到后面的位置去修车。那么我们考虑倒过来,去考虑倒数第\(i\)个来修车的人的贡献,显然这个贡献是\(c\cdot i\)。然后接下来就肥肠简单了,,,
代码:
/************************************************************** Problem: 1070 User: danihao123 Language: C++ Result: Accepted Time:576 ms Memory:13928 kb ****************************************************************/ #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <utility> #include <algorithm> #include <queue> #include <cassert> typedef long long ll; int m, n; const int maxno = 100005; const int maxe = 400005; int first[maxno]; int next[maxe], from[maxe], to[maxe], flow[maxe], cap[maxe]; ll cost[maxe]; int gcnt = 0; void add_edge(int u, int v, int f, ll c) { gcnt ++; next[gcnt] = first[u]; first[u] = gcnt; from[gcnt] = u; to[gcnt] = v; cap[gcnt] = f; flow[gcnt] = 0; cost[gcnt] = c; } int rev(int i) { return ((i - 1) ^ 1) + 1; } void ins_edge(int u, int v, int f, ll c = 0LL) { #ifdef LOCAL printf("Inserting Edge (%d, %d, %d, %lld)\n", u, v, f, c); #endif add_edge(u, v, f, c); add_edge(v, u, 0, -c); } const ll LINF = 0x7f7f7f7f7f7f7f7fLL; int tot; bool spfa(int s, int t, int &f, ll &c) { static ll d[maxno]; static bool inq[maxno]; static int a[maxno], p[maxno]; std::fill(d, d + tot + 1, LINF); std::fill(inq, inq + tot + 1, false); std::fill(a, a + tot + 1, 0); std::fill(p, p + tot + 1, 0); d[s] = 0; std::queue<int> Q; Q.push(s); inq[s] = true; a[s] = 0x7fffffff; while(!Q.empty()) { int u = Q.front(); Q.pop(); inq[u] = false; for(int i = first[u]; i; i = next[i]) { if(cap[i] > flow[i]) { int v = to[i]; if(d[v] > d[u] + cost[i]) { d[v] = d[u] + cost[i]; a[v] = std::min(a[u], cap[i] - flow[i]); p[v] = i; if(!inq[v]) { Q.push(v); inq[v] = true; } } } } } if(a[t] == 0) return false; f += a[t]; c += (ll(a[t])) * d[t]; for(int e = p[t]; e; e = p[from[e]]) { flow[e] += a[t]; flow[rev(e)] -= a[t]; } return true; } void mcmf(int s, int t, int &f, ll &c) { while(spfa(s, t, f, c)); } int pos[105][105][2]; int main() { scanf("%d%d", &m, &n); int s = 0, t = 1; tot = 1; for(int i = 1; i <= n; i ++) { ins_edge(s, ++ tot, 1); } for(int i = 1; i <= m; i ++) { for(int j = 1; j <= n; j ++) { pos[i][j][0] = ++ tot; pos[i][j][1] = ++ tot; ins_edge(tot - 1, tot, 1); ins_edge(tot, t, 1); } } for(int i = 1; i <= n; i ++) { for(int j = 1; j <= m; j ++) { int T; scanf("%d", &T); for(int k = 1; k <= n; k ++) { int id = pos[j][k][0]; int id2 = pos[j][k][1]; ins_edge(i + 1, id, 1, k * T); } } } int f = 0; ll c = 0; mcmf(s, t, f, c); #ifdef LOCAL printf("%d\n", f); #endif printf("%.2lf\n", (double(c)) / (double(n))); return 0; }