修车[SCOI2007]
题目传送门
1383. [SCOI 2007] 修车
★★★ 输入文件:scoi2007_repair.in
输出文件:scoi2007_repair.out
简单对比
时间限制:1 s 内存限制:256 MB
同一时刻有N位车主带着他们的爱车来到了汽车维修中心。维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的。现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最小。
说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间。
输入
第一行有两个数M,N,表示技术人员数与顾客数。
接下来n行,每行m个整数。第i+1行第j个数表示第j位技术人员维修第i辆车需要用的时间T。
输出
最小平均等待时间,答案精确到小数点后2位。
样例
repair.in
2 2
3 2
1 4
repair.out
1.50
数据范围:
(2<=M<=9,1<=N<=60), (1<=T<=1000)
求平均时间最小等于求每个人等的总时间最小。
如果一个人可以多线程工作的话这题就很好做了,然而如果一个人干完一个活才能干下一个,就要考虑前面的对后面的影响。对于一个工人来说,假设他修了n辆车,那么这n个车主等的总时间为w1*n+w2*(n-1)+...+wn*1(wi表示该工人修第i辆车的耗时),也就是说倒数第i辆车对总时间的贡献为w*i。所以我们把每个工人分出n个时段,每个第i个时段的耗时为i*w。最后跑一边最小费用最大流即可。
具体建模方式:n辆车与n*m个工人时段分属两个不同集合。第i辆车与第j个工人的第k个时段之间连容量为1,费用为k*wi,j的边。s向每辆车连容量为1,费用为0的边。每个工人时段向t连容量为1,费用为0的边。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #include<bitset> 7 #define LL long long 8 #define RI register int 9 using namespace std; 10 const int INF = 0x7ffffff ; 11 const int N = 60 + 2 ; 12 const int M = 9 + 2 ; 13 const int NN = 600 + 10 ; 14 const int FN = 1000 + 10 ; 15 const int MM = 1e6 + 10 ; 16 17 inline int read() { 18 int k = 0 , f = 1 ; char c = getchar() ; 19 for( ; !isdigit(c) ; c = getchar()) 20 if(c == '-') f = -1 ; 21 for( ; isdigit(c) ; c = getchar()) 22 k = k*10 + c-'0' ; 23 return k*f ; 24 } 25 struct Edge { 26 int to, next, flow, cost ; 27 }e[MM] ; 28 int n, m, s, t, ansf, ansc ; int head[FN], dis[FN] ; bool vis[FN] ; 29 inline void add_edge(int x,int y,int ff,int cc) { 30 static int cnt = 1 ; 31 e[++cnt].to = y, e[cnt].next = head[x], head[x] = cnt, e[cnt].flow = ff, e[cnt].cost = cc ; 32 e[++cnt].to = x, e[cnt].next = head[y], head[y] = cnt, e[cnt].flow = 0, e[cnt].cost = -cc ; 33 } 34 35 inline bool spfa() { 36 for(int i=1;i<=t;i++) dis[i] = INF ; dis[s] = 0 ; 37 deque<int>q ; q.push_back(s) ; bitset<FN>inq ; inq[s] = 1 ; 38 while(!q.empty()) { 39 int x = q.front() ; q.pop_front() ; inq[x] = 0 ; 40 for(int i=head[x];i;i=e[i].next) { 41 int y = e[i].to ; if(!e[i].flow) continue ; 42 if(dis[y] > dis[x]+e[i].cost) { 43 dis[y] = dis[x]+e[i].cost ; 44 if(!inq[y]) { 45 inq[y] = 1 ; 46 if(!q.empty() && dis[y] < dis[q.front()]) q.push_front(y) ; 47 else q.push_back(y) ; 48 } 49 } 50 } 51 } 52 return dis[t] < INF ; 53 } 54 int FFdfs(int x,int minflow) { 55 vis[x] = 1 ; 56 if(x == t || !minflow) return minflow ; 57 int fflow = 0 ; 58 for(int i=head[x];i;i=e[i].next) { 59 int y = e[i].to ; if(!e[i].flow || vis[y] || dis[y] != dis[x]+e[i].cost) continue ; 60 int temp = FFdfs(y,min(minflow,e[i].flow)) ; 61 fflow += temp, minflow -= temp ; 62 e[i].flow -= temp, e[i^1].flow += temp ; 63 ansc += temp*e[i].cost ; 64 if(!minflow) break ; 65 } 66 return fflow ; 67 } 68 69 int main() { 70 freopen("scoi2007_repair.in","r",stdin) ; 71 freopen("scoi2007_repair.out","w",stdout) ; 72 m = read(), n = read() ; s = n+NN+1, t = s+1 ; 73 for(int i=1;i<=n;i++) { 74 add_edge(s,i+NN,1,0) ; 75 for(int j=1;j<=m;j++) { 76 int x = read() ; 77 for(int k=1;k<=n;k++) { 78 add_edge(i+NN,(j-1)*n+k,1,k*x) ; 79 } 80 } 81 } 82 for(int i=1;i<=n*m;i++) add_edge(i,t,1,0) ; 83 while(spfa()) { 84 vis[t] = 1 ; 85 while(vis[t]) { 86 memset(vis,0,sizeof(vis)) ; 87 ansf += FFdfs(s,INF) ; 88 } 89 } 90 double ans = (double)ansc/(double)n ; 91 printf("%.2lf",ans) ; 92 return 0 ; 93 }