Bzoj1070 [SCOI2007]修车

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 5325  Solved: 2217

Description

  同一时刻有N位车主带着他们的爱车来到了汽车维修中心。维修中心共有M位技术人员,不同的技术人员对不同
的车进行维修所用的时间是不同的。现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最
小。 说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间。

Input

  第一行有两个m,n,表示技术人员数与顾客数。 接下来n行,每行m个整数。第i+1行第j个数表示第j位技术人
员维修第i辆车需要用的时间T。

Output

  最小平均等待时间,答案精确到小数点后2位。

Sample Input

2 2
3 2
1 4

Sample Output

1.50

HINT

数据范围: (2<=M<=9,1<=N<=60), (1<=T<=1000)

Source

网络流 费用流

……这题怎么这么像网络流?(悄悄百度)真是网络流啊………

把每个工人拆成n个点,这n个点分别向T连边,容量为1(同一时刻只能修一辆车),第i个点费用为i*(读入的花费)。

  ↑第i个点表示工人倒数第i个修这辆车,对总时间的贡献为等待的人数i*花费时间

跑费用流即可

 1 /*by SilverN*/
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 #include<vector>
 8 #include<queue>
 9 using namespace std;
10 const int mxn=1010;
11 int read(){
12     int x=0,f=1;char ch=getchar();
13     while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
14     while(ch>=‘0‘ && ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
15     return x*f;
16 }
17 struct edge{
18     int u,v,nxt,f,w;
19 }e[mxn*100];
20 int hd[mxn],mct=1;
21 void add_edge(int u,int v,int f,int w){
22     e[++mct].v=v;
23     e[mct].u=u;
24     e[mct].nxt=hd[u];
25     e[mct].f=f;e[mct].w=w;
26     hd[u]=mct;return;
27 }
28 void insert(int u,int v,int f,int w){
29     add_edge(u,v,f,w); add_edge(v,u,0,-w);return;
30 }
31 int S,T;
32 int dis[mxn],pre[mxn];
33 int n,m;
34 queue<int>q;
35 bool inq[mxn];
36 void SPFA(int s){
37     memset(dis,0x3f,sizeof dis);
38     memset(pre,-1,sizeof pre);
39     dis[s]=0;q.push(s);inq[s]=1;
40     while(!q.empty()){
41         int u=q.front();q.pop();inq[u]=0;
42         for(int i=hd[u];i;i=e[i].nxt){
43             int v=e[i].v;
44             if(e[i].f && dis[v]>dis[u]+e[i].w){
45                 dis[v]=dis[u]+e[i].w;
46                 pre[v]=i;
47                 if(!inq[v]){
48                     inq[v]=1;
49                     q.push(v);
50                 }
51             }
52         }
53     }
54     return;
55 }
56 int mxflow(int s,int t){
57     SPFA(s);
58     int res=0;
59     while(pre[t]!=-1){
60         int tmp=0x3f3f3f3f;
61         for(int i=pre[t];i!=-1;i=pre[e[i].u]){
62             tmp=min(tmp,e[i].f);
63         }
64         res+=dis[t]*tmp;
65         for(int i=pre[t];i!=-1;i=pre[e[i].u]){
66             e[i].f-=tmp;
67             e[i^1].f+=tmp;
68         }
69         SPFA(s);
70     }
71     return res;
72 }
73 int main(){
74     int i,j,w;
75     m=read();n=read();
76     S=0;T=n+m*n+1;
77     for(i=1;i<=n;i++){
78         insert(S,i,1,0);
79     }
80     for(i=1;i<=n;i++){
81         for(j=1;j<=m;j++){
82             w=read();
83             for(int k=1;k<=n;k++){
84                 insert(i,j+n+m*(k-1),1,w*k);
85             }
86         }
87     }
88     for(i=1;i<=m;i++)
89         for(j=1;j<=n;j++)
90             insert(i+n+m*(j-1),T,1,0);
91     int ans=mxflow(S,T);
92 //    printf("!! %d\n",ans);
93     printf("%.2f\n",(double)ans/n);
94     return 0;
95 }

上面那个跑了1000+ms,一看排行榜震惊了,怎么前面全是几十ms跑完的

在黄学长博客看到了神奇的zkw费用流,(看上去像是Dinic和SPFA的结合体),学习一下↓

这样写快了一半。

然而还是不知道几十ms怎么做到的啊

  1 /*by SilverN*/
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<cmath>
  7 #include<vector>
  8 #include<queue>
  9 using namespace std;
 10 const int mxn=1010;
 11 int read(){
 12     int x=0,f=1;char ch=getchar();
 13     while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
 14     while(ch>=‘0‘ && ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
 15     return x*f;
 16 }
 17 struct edge{
 18     int u,v,nxt,f,w;
 19 }e[mxn*100];
 20 int hd[mxn],mct=1;
 21 void add_edge(int u,int v,int f,int w){
 22     e[++mct].v=v;
 23     e[mct].u=u;
 24     e[mct].nxt=hd[u];
 25     e[mct].f=f;e[mct].w=w;
 26     hd[u]=mct;return;
 27 }
 28 void insert(int u,int v,int f,int w){
 29     add_edge(u,v,f,w); add_edge(v,u,0,-w);return;
 30 }
 31 int S,T;
 32 int dis[mxn],pre[mxn];
 33 int n,m;
 34 queue<int>q;
 35 bool inq[mxn];
 36 bool mark[mxn];
 37 bool SPFA(int s){
 38     memset(inq,0,sizeof inq);
 39     for(int i=0;i<=T;i++)dis[i]=0x3f3f3f3f;
 40     dis[T]=0;q.push(T);inq[T]=1;
 41     while(!q.empty()){
 42         int u=q.front();q.pop();inq[u]=0;
 43         for(int i=hd[u];i;i=e[i].nxt){
 44             int v=e[i].v;
 45             if(e[i^1].f && dis[v]>dis[u]-e[i].w){
 46                 dis[v]=dis[u]-e[i].w;
 47 //                pre[v]=i;
 48                 if(!inq[v]){
 49                     inq[v]=1;
 50                     q.push(v);
 51                 }
 52             }
 53         }
 54     }
 55     if(dis[S]==0x3f3f3f3f)return 0;
 56     return 1;
 57 }
 58 int ans=0;
 59 int DFS(int x,int f){
 60     if(x==T){inq[T]=1;return f;}
 61     int used=0,w;
 62     inq[x]=1;
 63     for(int i=hd[x];i;i=e[i].nxt){
 64         int v=e[i].v;
 65         if(!inq[v] && e[i].f && dis[x]-e[i].w==dis[v]){
 66             w=f-used;
 67             w=DFS(v,min(e[i].f,w));
 68             ans+=w*e[i].w;
 69             e[i].f-=w;    e[i^1].f+=w;
 70             used+=w;
 71             if(used==f)return f;
 72         }
 73     }
 74     return used;
 75 }
 76
 77 void mxflow(int s,int t){
 78     while(SPFA(s)){
 79         inq[T]=1;
 80         while(inq[T]){
 81             memset(inq,0,sizeof inq);
 82             DFS(S,0x3f3f3f3f);
 83         }
 84     }
 85     return;
 86 }
 87 int main(){
 88     int i,j,w;
 89     m=read();n=read();
 90     S=0;T=n+m*n+1;
 91     for(i=1;i<=n;i++){
 92         insert(S,i,1,0);
 93     }
 94     for(i=1;i<=n;i++){
 95         for(j=1;j<=m;j++){
 96             w=read();
 97             for(int k=1;k<=n;k++){
 98                 insert(i,j+n+m*(k-1),1,w*k);
 99             }
100         }
101     }
102     for(i=1;i<=m;i++)
103         for(j=1;j<=n;j++)
104             insert(i+n+m*(j-1),T,1,0);
105     mxflow(S,T);
106     printf("%.2f\n",(double)ans/n);
107     return 0;
108 }
时间: 2024-10-06 22:10:37

Bzoj1070 [SCOI2007]修车的相关文章

[bzoj1070][SCOI2007]修车_费用流

修车 bzoj-1070 SCOI-2007 题目大意:有m个人要修n台车,每个工人修不同的车的时间不同,问将所有的车都修完,最少需要花费的时间. 注释:$2\le m\le 9$,$1\le n \le 60$ 想法:想起了那句话...(如果题面复杂,dp状态不可描述,一看数据范围发现才几百,那八成是网络流了),一般这句话都是对的,除了那次在CF上遇到的爆搜.. ... 关于这道题,网上有题解在边上做技巧(完全没明白这样的意义),我的做法时拆点.将每个点拆成n个,然后在这些被拆的点与车之间连边

[BZOJ1070][SCOI2007]修车(最小费用最大流)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1070 分析: 把每个工人拆成N个点.记为A[i,j]表示第i个工人修倒数第j辆车. 每个车跟所有N*M个工人拆出的点连边.流量为1,费用为time[i,j]*k. 源和每辆车连边,N*M个点和汇连边,流量都为1,费用同为0. 为什么这么建呢?因为如果某个工人修了某辆车,那么只会对这个工人以后修的车的时间有影响,对已经修完的没影响,于是可以倒过来考虑.

[bzoj1070][SCOI2007]修车[ 网络流]

把每个工人拆成N个点.记为A[i,j]表示第i个工人修倒数第j辆车.每个车跟所有N*M个工人拆出的点连边.流量为1,费用为$time[i,j]*k$.源和每辆车连边,N*M个点和汇连边,流量都为1,费用同为0. 1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cstring> 6 #include &

[BZOJ1070] [SCOI2007] 修车 (费用流 &amp; 动态加边)

Description 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最小. 说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间. Input 第一行有两个m,n,表示技术人员数与顾客数. 接下来n行,每行m个整数.第i+1行第j个数表示第j位技术人员维修第i辆车需要用的时间T. Output 最小平均等待时间,答案精确到小数点后2位

[SCOI2007]修车

1070: [SCOI2007]修车 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 6007  Solved: 2559 [Submit][Status][Discuss] Description 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同 的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最 小. 说明:顾客的等待时间是指从他把车送至维修中心

BZOJ 1070: [SCOI2007]修车(最小费用最大流)

建图很神奇..建完图其实就是裸的费用流了.. -------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<vector> #include<queue> #define rep(i,n) for(int i

bzoj 1070: [SCOI2007]修车 -- 费用流

1070: [SCOI2007]修车 Time Limit: 1 Sec  Memory Limit: 128 MB Description 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最小. 说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间. Input 第一行有两个m,n,表示技术人员数与顾客数. 接下来n行,每行m个整数.第

[bzoj1070] [洛谷P2053] [SCOI2007] 修车

Description 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同 的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最 小. 说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间. Input 第一行有两个m,n,表示技术人员数与顾客数. 接下来n行,每行m个整数.第i+1行第j个数表示第j位技术人 员维修第i辆车需要用的时间T. Output 最小平均等待时间,答案精确到小数点

[BZOJ 1070][SCOI2007]修车(费用流)

Description 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最小. 说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间. Solution 非常经典的建图方式,将每一位技术人员拆成n个点分别他是表示倒数第几个修车的,倒数第k个修车的技术人员对所有在等待的人的贡献是tim[i][j]*k #include<iostream>