bzoj1070 [SCOI2007]修车
1070: [SCOI2007]修车
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 6643 Solved: 2870
[Submit][Status][Discuss]
Description
同一时刻有N位车主带着他们的爱车来到了汽车维修中心。维修中心共有M位技术人员,不同的技术人员对不同
的车进行维修所用的时间是不同的。现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最
小。 说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间。
Input
第一行有两个m,n,表示技术人员数与顾客数。 接下来n行,每行m个整数。第i+1行第j个数表示第j位技术人
员维修第i辆车需要用的时间T。
Output
最小平均等待时间,答案精确到小数点后2位。
Sample Input
3 2
1 4
Sample Output
HINT
数据范围: (2<=M<=9,1<=N<=60), (1<=T<=1000)
分析:这道题和bzoj1449很像.
先来看看它们有什么相似之处.
1.最后的答案是每一部分的贡献之和.
2.每一部分的贡献是不确定的,有单调性.
3.要用费用流解决.(求最值,有数量限制)
解决这类问题的方法就是拆边!
这道题中修一辆车的贡献就是让它之后的车主等待的时间和. 如果只有一位修车工,当前的车是第i辆被修的,那么它的贡献就是(n - i + 1) * 所花的时间. 建图跑费用流,可以A掉.
这种解法是有问题的,A掉只是碰巧罢了.修车的费用随着i的增加是递减的,最小费用流肯定先跑费用最小的那条边. 那么第1辆车就会被最后给修理. 在只有一个修车工的时候是可以的,但是多个修车工就不行了. 因为第一个修车工可能不会修n辆车,他可能只会修n-1辆车,而之前的方案却安排第一辆车是他修的第n辆车,这显然是不合法的.
所以问题有两个:1.每个人修多少辆车不知道.2.费用是递减的,就算确定了修多少辆车可能还是不合法.
怎么办呢?换个定义就好了......
令当前的车是倒数第i辆被修的,那么它的贡献就是i*所花的时间. 贡献递增. 而且注意关键词:倒数. 说明在它之间的车都已经被修了,不会出现不合法的情况.有那么一点哲学的意味......
最奇葩的是,两种方法都能A掉,无力吐槽.
#include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #include<queue> using namespace std; const int inf = 1000000000; int n, m, to[100000], nextt[100000], head[100000], tot, w[100000], cost[100000], vis[100000], d[100000], p[100000], s, t; void add(int x, int y, int c, int h) { to[tot] = y; w[tot] = c; cost[tot] = h; nextt[tot] = head[x]; head[x] = tot++; } bool spfa() { memset(vis, 0, sizeof(vis)); memset(d, 0x3f, sizeof(d)); memset(p, -1, sizeof(p)); d[s] = 0; queue <int> q; q.push(s); vis[s] = 1; while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for (int i = head[u];i != -1; i = nextt[i]) { if (w[i]) { int v = to[i]; if (d[u] + cost[i] < d[v]) { d[v] = cost[i] + d[u]; p[v] = i; if (!vis[v]) { q.push(v); vis[v] = 1; } } } } } if (p[t] != -1) return true; return false; } int solve_min() { int res = 0; int f = 0; while (spfa()) { int flow = inf; for (int i = t;i != s; i = to[p[i] ^ 1]) flow = min(w[p[i]], flow); for (int i = t; i != s; i = to[p[i] ^ 1]) { w[p[i]] -= flow; w[p[i] ^ 1] += flow; res += flow * cost[p[i]]; } f += flow; } return res; } int main() { memset(head, -1, sizeof(head)); scanf("%d%d", &m, &n); s = 0, t = n * m + n + 1; for (int i = 1; i <= n; ++i) { add(i + m * n, t, 1, 0); add(t, i + m * n, 0, 0); } for (int j = 1; j <= m; ++j) { for (int k = 1; k <= n; ++k) { add(s, (j - 1) * n + k, 1, 0); add((j - 1) * n + k, s, 0, 0); } } 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++) { add((j - 1) * n + k, i + m * n, 1, t * k); add(i + m * n, (j - 1) * n + k, 0, -t * k); } } int ans = solve_min(); printf("%.2lf", 1.0 * ans / n); return 0; }