[BZOJ 1070] [SCOI2007] 修车 【费用流】
题目链接:BZOJ - 1070
题目分析
首先想到拆点,把每个技术人员拆成 n 个点,从某个技术人员拆出的第 i 个点,向某辆车连边,表示这是这个技术人员修的倒数第 i 辆车。那么这一次修车对整个答案的贡献就是,i * Time[j][k]。 j 是车的编号,k 是技术人员编号。因为这辆车以及之后这个人要修的车的等待时间都增加了 Time[j][k], 所以包括这辆车在内一共有 i 辆车的等待时间加上了这次修车的时间。这样倒着考虑就可以用边的费用很简便的表示修车使所有人增加的时间了。从 S 到所有技术人员拆出的所有点连边,容量 1 , 费用 0 ;从每辆车向 T 连边,容量 1 ,费用 0 。
最后跑一边最小费用最大流就是所有车等待时间的和。
代码
- #include <iostream>
- #include <cstdio>
- #include <cstring>
- #include <cstdlib>
- #include <cmath>
- #include <algorithm>
- #include <queue>
- using namespace std;
- const int MaxN = 1000 + 5, MaxM = 100000 + 5, INF = 999999999;
- int n, m, S, T, Ans;
- int Time[60 + 5][9 + 5], d[MaxN];
- bool Used[MaxN];
- queue<int> Q;
- inline int gmin(int a, int b) {return a < b ? a : b;}
- inline int gmax(int a, int b) {return a > b ? a : b;}
- struct Edge
- {
- int u, v, w, Cost;
- Edge *Next, *Other;
- } E[MaxM], *P = E, *Point[MaxN], *Pre[MaxN];
- inline void AddEdge(int x, int y, int z, int Ct) {
- Edge *Q = ++P; ++P;
- P -> u = x; P -> v = y; P -> w = z; P -> Cost = Ct;
- P -> Next = Point[x]; Point[x] = P; P -> Other = Q;
- Q -> u = y; Q -> v = x; Q -> w = 0; Q -> Cost = -Ct;
- Q -> Next = Point[y]; Point[y] = Q; Q -> Other = P;
- }
- bool Found() {
- memset(d, 0x7f, sizeof(d));
- memset(Used, 0, sizeof(Used));
- d[S] = 0; Used[S] = true; Q.push(S);
- while (!Q.empty()) {
- int x = Q.front();
- Used[x] = false;
- Q.pop();
- for (Edge *j = Point[x]; j; j = j -> Next) {
- if (j -> w && d[j -> v] > d[x] + j -> Cost) {
- d[j -> v] = d[x] + j -> Cost;
- Pre[j -> v] = j;
- if (!Used[j -> v]) {
- Used[j -> v] = true;
- Q.push(j -> v);
- }
- }
- }
- }
- if (d[T] < INF) return true;
- return false;
- }
- void Augment() {
- int Flow;
- Flow = INF;
- for (Edge *j = Pre[T]; j; j = Pre[j -> u]) Flow = gmin(Flow, j -> w);
- for (Edge *j = Pre[T]; j; j = Pre[j -> u]) {
- j -> w -= Flow;
- j -> Other -> w += Flow;
- }
- Ans += Flow * d[T];
- }
- int main()
- {
- scanf("%d%d", &m, &n);
- for (int i = 1; i <= n; ++i) {
- for (int j = 1; j <= m; ++j) {
- scanf("%d", &Time[i][j]);
- }
- }
- S = n * m + n + 1; T = S + 1;
- for (int i = 1; i <= n * m; ++i) AddEdge(S, i, 1, 0);
- for (int i = n * m + 1; i <= n * m + n; ++i) AddEdge(i, T, 1, 0);
- for (int i = 1; i <= m; ++i) {
- for (int j = 1; j <= n; ++j) {
- for (int k = 1; k <= n; ++k) {
- AddEdge((i - 1) * n + j, n * m + k, 1, j * Time[k][i]);
- }
- }
- }
- Ans = 0;
- while (Found()) Augment();
- printf("%.2lf\n", (double)Ans / (double)n);
- return 0;
- }
[BZOJ 1070] [SCOI2007] 修车 【费用流】的更多相关文章
- bzoj 1070: [SCOI2007]修车 费用流
1070: [SCOI2007]修车 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 2785 Solved: 1110[Submit][Status] ...
- BZOJ.1070.[SCOI2007]修车(费用流SPFA)
题目链接 /* 神tm看错题*2.. 假如人员i依次维修W1,W2,...,Wn,那么花费的时间是 W1 + W1+W2 + W1+W2+W3... = W1*n + W2*(n-1) + ... + ...
- BZOJ 1070: [SCOI2007]修车 [最小费用最大流]
1070: [SCOI2007]修车 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 4936 Solved: 2032[Submit][Status] ...
- bzoj 1070 [SCOI2007]修车(最小费用最大流)
1070: [SCOI2007]修车 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 3515 Solved: 1411[Submit][Status] ...
- [BZOJ1070][SCOI2007]修车 费用流
1070: [SCOI2007]修车 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 6209 Solved: 2641[Submit][Status] ...
- BZOJ 1070 拆点 费用流
1070: [SCOI2007]修车 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 5860 Solved: 2487[Submit][Status] ...
- 【BZOJ 1070】[SCOI2007]修车 费用流
就是拆个点限制一下(两点一排一大片),这道题让我注意到了限制这个重要的词.我们跑网络流跑出来的图都是有一定意义的,一般这个意义就对应了问题的一种方案,一般情况下跑一个不知道对不对的方案是相对容易的我们 ...
- 【BZOJ1070】[SCOI2007]修车 费用流
[BZOJ1070][SCOI2007]修车 Description 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的. ...
- bzoj 1070 [SCOI2007]修车——网络流(拆边)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1070 后面还有几辆车在这个人这儿修,自己这辆车的时间对总时间的贡献就要多乘上几倍. 所以可以 ...
随机推荐
- OpenCV 2.4.9
2014.4.25 感谢那些參加开发.发送错误报告以及通过其它方式帮助我们的全部人和公司. 源代码如今已经可以从SourceForge和Github上下载了. 2.4.9版本号的帮助文章也更新到如今的 ...
- 在RichTextBox控件中插入图片
. 在RichTextBox控件中插入图片 关键点 . 实现过程 . public void ShowInsertImageDlg() { OpenFileDialog OpenFileD ...
- java实现渐变效果工具
[html] view plain copy package gradient; import java.awt.Color; import java.awt.Dimension; import ja ...
- MapReduce计数器
1.MapReduce计数器是什么? 计数器是用来记录job的执行进度和状态的.它的作用可以理解为日志.我们可以在程序的某个位置插入计数器,记录数据或者进度的变化情况. 2.MapReduce计数器能 ...
- eclipse-SDK-3.7-win32;eclipse-java-indigo-win32;eclipse-jee-indigo-win32 区别(ZZ)
eclipse-SDK-3.7-win32:eclipse-java-indigo-win32:eclipse-jee-indigo-win32 三个都是用于win32,即windows系统的32位机 ...
- Maven学习总结——聚合与继承
一.聚合 如果我们想一次构建多个项目模块,那我们就需要对多个项目模块进行聚合 1.1.聚合配置代码 1 <modules> 2 <module>模块一</module&g ...
- Oracle 卸载 不干净
关闭oracle相关的服务 注册表删除(可能因为oracle及windows的版本不同注册表信息也有些差异): 开始è输入regedit 打开注册表编辑器删除下面的目录 HKEY_LOCAL_MACH ...
- win7、xp下Meclipse SVN用户名修改
Meclipse SVN用户名修改,在网上查找后发现如下方法: 1.查看你的Eclipse中使用的是什么SVNInterface windows>preference>Team>SV ...
- 基于JAVA网络编程的聊天小程序
package com.neusoft.edu.socket; import java.io.BufferedReader; import java.io.IOException; import ja ...
- Linux试玩指令开机关机
Linux内核最初只是由芬兰人李纳斯·托瓦兹(Linus Torvalds)在赫尔辛基大学上学时出于个人爱好而编写的. Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和U ...