[BZOJ1070] [SCOI2007] 修车 (费用流 & 动态加边)
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)
Source
Solution
我目前为止一道费用流的模型都不会建T_T
构造一个图,左边$n*m$个点,表示第$j$个技术人员修的倒数第$i$辆车,右边$n$个点,表示第$k$辆车
源点向左边的点连$(w=1, cost=0)$的边,因为每个人同一时刻只能修一辆车
左边$m*n$个点再分别向右边$n$个点连边,左边第$(i, j)$个点向右边第$k$个点连$(w=INF, cost=i*t[i][j])$的边
相当于此时有$i$个人在等待着这辆车修完,代价就是等待的人数$*$修这辆车的时间
右边的点向汇点连$(w=1, cost=0)$的边,表示每辆车只能被一个人修
容易看出,此时最大流一定是$n$,每一条$w=1$的流表示第$j$个人修的倒数第$i$辆车是第$k$辆车
那么最小费用除以$n$就是我们的答案
总点数是$2+m*n+n$,不超过$602$;边数是$2*(m*n+m*n*n+n)$,不超过$70000$
欸我好像擅长将源点设成n+1将汇点设成n+2...
可以加一个不知道是不是优化的优化:中间的所有边的边权可以只设为$1$,因为这条边本身流量最大值也是$1$
(如果这条边流过,其边权变成了$0$,貌似可以使$SPFA$中该点的入队次数变少一些...只是本人猜测)
#include <bits/stdc++.h>
using namespace std;
const int INF = ;
struct edge
{
int u, v, w, c, nxt;
}e[];
int n, fst[], t[][], etot = , level[];
int q[], pth[];
bool inq[]; void addedge(int u, int v, int w, int c)
{
e[++etot] = (edge){u, v, w, c, fst[u]}, fst[u] = etot;
e[++etot] = (edge){v, u, , -c, fst[v]}, fst[v] = etot;
} bool SPFA()
{
int front = , back, u;
memset(level, , sizeof(level));
level[n + ] = ;
q[back = ] = n + , inq[n + ] = true;
while(front != back)
{
u = q[(++front % )];
front %= , inq[u] = false;
for(int i = fst[u]; i; i = e[i].nxt)
if(e[i].w && level[e[i].v] > level[u] + e[i].c)
{
level[e[i].v] = level[u] + e[i].c;
pth[e[i].v] = i;
if(!inq[e[i].v])
{
q[(++back % )] = e[i].v;
back %= , inq[e[i].v] = true;
}
}
}
return level[n + ] < INF;
} int Edmond_Karp()
{
int flow = INF;
for(int i = pth[n + ]; i; i = pth[e[i].u])
flow = min(flow, e[i].w);
for(int i = pth[n + ]; i; i = pth[e[i].u])
e[i].w -= flow, e[i ^ ].w += flow;
return flow * level[n + ];
} int main()
{
int m, ptot, ans = ;
scanf("%d%d", &m, &n);
for(int i = ; i <= n; ++i)
for(int j = ; j <= m; ++j)
scanf("%d", &t[i][j]);
for(int i = ; i <= n; ++i)
addedge(i, n + , , );
ptot = n + ;
for(int i = ; i <= m; ++i)
for(int j = ; j <= n; ++j)
{
++ptot;
for(int k = ; k <= n; ++k)
addedge(ptot, k, , t[k][i] * j);
}
for(int i = n + ; i <= ptot; ++i)
addedge(n + , i, , );
while(SPFA())
ans += Edmond_Karp();
printf("%.2f\n", (double)ans / n);
return ;
}
但是!这道题的总时限是$1s$,这种图需要大概$1.4s$,严格来说是超时的
我们有一种优化方法:
如果第$j$个人没修倒数第$i$辆车,他一定不会修倒数第$i+1$、$i+2$...辆车
所以初始的图左边只需要有$m$个点,表示每个人的倒数第$1$辆车
当图中左边点$(j, i)$到右边点$k$流了$1$时,我们再将左边的$(j, i+1)$和右边的$k$连上边(权值和之前说的一样)
这样总点数是$2+m+n+n$,不超过$131$,总边数是$2*(m+m*n+n)+2*(n+2)*n$,不超过$10000$,EK党的胜利!
你们四不四洒,就不会合作修同一辆车吗
#include <bits/stdc++.h>
using namespace std;
const int INF = ;
struct edge
{
int u, v, w, c, nxt;
}e[];
int n, fst[], t[][], etot = , level[];
int q[], pth[], belong[], fin[], use;
bool inq[]; void addedge(int u, int v, int w, int c)
{
e[++etot] = (edge){u, v, w, c, fst[u]}, fst[u] = etot;
e[++etot] = (edge){v, u, , -c, fst[v]}, fst[v] = etot;
} bool SPFA()
{
int front = , back, u;
memset(level, , sizeof(level));
level[n + ] = ;
q[back = ] = n + , inq[n + ] = true;
while(front != back)
{
u = q[(++front % )];
front %= , inq[u] = false;
for(int i = fst[u]; i; i = e[i].nxt)
if(e[i].w && level[e[i].v] > level[u] + e[i].c)
{
level[e[i].v] = level[u] + e[i].c;
pth[e[i].v] = i;
if(!inq[e[i].v])
{
q[(++back % )] = e[i].v;
back %= , inq[e[i].v] = true;
}
}
}
return level[n + ] < INF;
} int Edmond_Karp()
{
for(int i = pth[n + ]; i; i = pth[e[i].u])
{
--e[i].w, ++e[i ^ ].w;
if(e[i].u == n + ) use = e[i].v;
}
return level[n + ];
} int main()
{
int m, ptot, ans = , k;
scanf("%d%d", &m, &n);
for(int i = ; i <= n; ++i)
for(int j = ; j <= m; ++j)
scanf("%d", &t[i][j]);
for(int i = ; i <= n; ++i)
addedge(i, n + , , );
ptot = n + ;
for(int i = ; i <= m; ++i)
{
belong[++ptot] = i, ++fin[i];
for(int j = ; j <= n; ++j)
addedge(ptot, j, , t[j][i]);
}
for(int i = n + ; i <= ptot; ++i)
addedge(n + , i, , );
while(SPFA())
{
ans += Edmond_Karp();
k = belong[++ptot] = belong[use], ++fin[k];
for(int i = ; i <= n; ++i)
addedge(ptot, i, , t[i][k] * fin[k]);
addedge(n + , ptot, , );
}
printf("%.2f\n", (double)ans / n);
return ;
}
[BZOJ1070] [SCOI2007] 修车 (费用流 & 动态加边)的更多相关文章
- [BZOJ1070][SCOI2007]修车 费用流
1070: [SCOI2007]修车 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 6209 Solved: 2641[Submit][Status] ...
- [bzoj1070][SCOI2007]修车——费用流
题目大意: 传送门 题解: 本题和(POJ3686)[http://poj.org/problem?id=3686]一题一模一样,而且还是数据缩小以后的弱化版QAQ,<挑战程序设计竞赛>一 ...
- 【BZOJ1070】[SCOI2007]修车 费用流
[BZOJ1070][SCOI2007]修车 Description 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的. ...
- 【bzoj2879】[Noi2012]美食节 费用流+动态加边
原文地址:http://www.cnblogs.com/GXZlegend 题目描述 CZ市为了欢迎全国各地的同学,特地举办了一场盛大的美食节.作为一个喜欢尝鲜的美食客,小M自然不愿意错过这场盛宴.他 ...
- bzoj 1070: [SCOI2007]修车 费用流
1070: [SCOI2007]修车 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 2785 Solved: 1110[Submit][Status] ...
- [BZOJ2879] [Noi2012] 美食节 (费用流 & 动态加边)
Description CZ市为了欢迎全国各地的同学,特地举办了一场盛大的美食节.作为一个喜欢尝鲜的美食客,小M自然不愿意错过这场盛宴.他很快就尝遍了美食节所有的美食.然而,尝鲜的欲望是难以满足的.尽 ...
- P2053 [SCOI2007]修车 费用流
$ \color{#0066ff}{ 题目描述 }$ 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的.现在需要安排这M ...
- [NOI2012][bzoj2879] 美食节 [费用流+动态加边]
题面 传送门 思路 先看看这道题 修车 仔细理解一下,这两道题是不是一样的? 这道题的不同之处 但是有一个区别:本题中每一种车有多个需求,但是这个好办,连边的时候容量涨成$p\lbrack i\rbr ...
- BZOJ 2879 美食节(费用流-动态加边)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2879 题意:有n道菜,每道菜需要b[i]份,m个厨师,第j个厨师做第i道菜需要时间a[i ...
随机推荐
- Install Centrifugo and quick start
Install Centrifugo and quick start Go is a perfect language - it gives developers an opportunity to ...
- 老男孩Python全栈开发(92天全)视频教程 自学笔记15
day15课程内容: 高阶函数 1.函数名可以进行赋值 2.函数名可以作为参数,也可以作为函数的返回值 def f(): print("高阶函数")def bar(a,b,c): ...
- oracle报表功能
需求是将指定的批量sql语句执行的结果通过脚本导出成txt或者能用excel打开的文件. oracle导出文件可以通过spool命令实现,通过bat脚本登录sqlplus,然后引入sql文件即可,源码 ...
- python>oop
oop即Object Oriented programming,面向对象编程 何为编程:特定的语法+数据结构+算法 编程范式就是从经验中总结的套路: 面向过程编程 适用于简单的脚本,一次任务是极好的, ...
- ACL访问控制列表
acl是基于文件系统的,所以支不支持acl在于使用什么文件系统. FAT32文件系统不支持权限,也不区分大小写 如果一个分区不是安装系统时分的分区,是一个新的分区的话,默认是不支持acl CentOS ...
- 后台模拟请求 HttpHelper 序列化 MD5 时间戳
使用场景 C# 服务器后台调用其他服务器并处理 场景 /// <summary> /// 获取用户信息 /// </summary> /// <param name=&q ...
- Linux CentOS7下安装python3
在CentOS7下,默认安装的就是python2.7,我现在来教大家如何安装python3: 1.首先安装python3.6可能使用的依赖 # yum -y install openssl-devel ...
- 第II篇PCI Express体系结构概述
虽然PCI总线取得了巨大的成功,但是随着处理器主频的不断提高,PCI总线提供的带宽愈发显得捉襟见肘.PCI总线也在不断地进行升级,其位宽和频率从最初的32位/33MHz扩展到64位/66MHz,而PC ...
- Android 4.4以上使用HttpURLConnection底层使用OkHttp实现的源码分析
研究了一下HttpURLConnection的源码: 在使用的时候都是通过URL.openConnection()来获取HttpURLConnection对象,然后调用其connect方法进行链接,所 ...
- phpexcle 导出数据 日期格式的问题
在使用phpexcle 读取excle中日期格式的出现了问题.特此记录 gmdate("Y-m-d H:i:s", PHPExcel_Shared_Date::ExcelToPHP ...