修车[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 }

 

转载于:https://www.cnblogs.com/zub23333/p/8849048.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值