[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 ...
随机推荐
- 【HTTP协议】---TCP三次握手和四次挥手
TCP三次握手和四次挥手 首先我们知道HTTP协议通常承载于TCP协议之上,HTTPS承载于TLS或SSL协议层之上 通过上面这张图我们能够知道. 在Http工作之前,Web浏览器通过网络和W ...
- 捋一捋js面向对象的继承问题
说到面向对象这个破玩意,曾经一度我都处于很懵逼的状态,那么面向对象究竟是什么呢?其实说白了,所谓面向对象,就是基于类这个概念,来实现封装.继承和多态的一种编程思想罢了.今天我们就来说一下这其中继承的问 ...
- hdu4148 Length of S(n)
Length of S(n) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)To ...
- JavaScript 历史漫谈
话说 JavaScript 其实是诞生在一个特殊的时期,20世纪90年代,正值第三次科技革命时期,互联网刚开始进入人们的生活.设想一下,在网速只有几十比特的那个时代,在登录注册时要花上很长一段时间等待 ...
- 创建Maven web工程不能解析EL表达式的解决办法
在web.xml中讲头部改为: <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee&qu ...
- 深入研究Node.js的底层原理和高级使用
深入研究Node.js的底层原理和高级使用
- PHP的错误机制
特别说明:文章的PHP版本使用5.5.32 PHP的错误级别 首先需要了解php有哪些错误.截至到php5.5,一共有16个错误级别 注意:尝试下面的代码的时候请确保打开error_log: erro ...
- 关于Mysql5.7高版本group by新特性报错
一个项目的开发到测试上线运营,团队对项目的管理不成熟会影响项目的开发效率.由于项目是我刚接手,独自在Centos搭建PHP环境,所以就考虑使用高版本,选择了Mysql5.7,本地开发环境还是Windo ...
- C++学习笔记第一天:基础
前言 N年前学的C,经过VB.JAVA.JS.C#等后辈的轮番蹂躏,当初学的那点儿东西早就还给老师了 现在有了在桌面端实现 Native + Web 的初衷,需要利用CEF开源组件来封装这个Nativ ...
- PAT All Roads Lead to Rome 单源最短路
思路:单源最短路末班就好了,字符串映射成数字处理. AC代码 //#define LOCAL #include <stdio.h> #include <string.h> #i ...