培训补坑(day4:网络流建模与二分图匹配)
补坑时间到QAQ
好吧今天讲的是网络流建模与二分图匹配。。。
day3的网络流建模好像说的差不多了、(囧)
那就接着补点吧。。
既然昨天讲了建图思想,那今天就讲讲网络流最重要的技巧:拆点。
拆点,顾名思义,就是把一个状态拆成数个点以满足题目要求。
今天主要围绕一个例题来讲:修车。(虽然是丧题,但是却是网络流算法思想实现的典例)
——————————————————我是分割线——————————————————
题目:
同一时刻有位车主带着他们的爱车来到了汽车维修中心。维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的。现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最小。 说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间。注:(2<=m<=9,1<=n<=60)
——————————————————我是分割线——————————————————
其实我一开始看到这题,我都没看出来这是网络流(真是太弱了)
然后我去网络上看了题解。
首先我们知道一个工人修一辆车就会让其余没有修过车的time增加,所以我们发现如果考虑第i个工人修第j辆车的话,会发现时间是不确定的。
但是如果我们倒着过来计算的话,那么我们就能够计算时间了。
所以我们将n个工人每一个分为m个点,表示第i个工人修倒数第j辆车,然后每一条边的费用就是time*j,表示等待的时间,从S到每一个点连边,从每一个点到T连边,然后我们跑最小费用最大流就好了。
对于费用流不懂的同学们可以去我的博客上看看。(暂时没写,以后补坑)
下面附上例题代码
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
int ans;
int go[],tot,S,T,first[],next[],flow[];
int cost[],c[],edge[],from[],a[][];
int nodes,b[][],n,m,op[],dis[],vis[];
int read(){
int t=,f=;char ch=getchar();
while (ch<''||ch>''){if (ch=='-') f=-;ch=getchar();}
while (''<=ch&&ch<=''){t=t*+ch-'';ch=getchar();}
return t*f;
}
void insert(int x,int y,int z,int l){
tot++;
go[tot]=y;
next[tot]=first[x];
first[x]=tot;
flow[tot]=z;
cost[tot]=l;
}
void add(int x,int y,int z,int l){
insert(x,y,z,l);op[tot]=tot+;
insert(y,x,,-l);op[tot]=tot-;
}
bool spfa(){
for (int i=;i<=T;i++) dis[i]=0x3f3f3f3f,vis[i]=;
dis[S]=;
int h=,t=;
c[]=S;
while (h<=t){
int now=c[h++];
for (int i=first[now];i;i=next[i]){
int pur=go[i];
if (flow[i]&&dis[pur]>dis[now]+cost[i]){
dis[pur]=dis[now]+cost[i];
from[pur]=now;
edge[pur]=i;
if (vis[pur]) continue;
vis[pur]=;
c[++t]=pur;
}
}
vis[now]=;
}
return dis[T]!=0x3f3f3f3f;
}
void updata(){
int mn=0x7fffffff;
for (int i=T;i!=S;i=from[i]){
mn=std::min(mn,flow[edge[i]]);
}
for (int i=T;i!=S;i=from[i]){
flow[edge[i]]-=mn;
flow[op[edge[i]]]+=mn;
ans+=mn*cost[edge[i]];
}
}
int main(){
m=read();n=read();
for (int i=;i<=n;i++){
for (int j=;j<=m;j++){
a[i][j]=read();
}
}
S=,T=n*m+n+;
for (int i=;i<=n;i++)
add(S,i,,);
nodes=n;
for (int i=;i<=m;i++)
for (int k=;k<=n;k++)
b[i][k]=++nodes,add(nodes,T,,);
for (int i=;i<=n;i++)
for (int j=;j<=m;j++)
for (int k=;k<=n;k++)
add(i,b[j][k],,k*a[i][j]);
while (spfa()) updata();
double Ans=(double)ans/n;
printf("%.2f\n",Ans);
}
接下来我们讲讲二分图匹配。
二分图匹配就是说有一个二层图,层数不同的两个点之间有一些边,问如何选取一些边,使得一个点只被一条边选中,而且边的个数最多(求最大匹配)
其中最主要的算法就是匈牙利算法,朴素而迅速。
我们上图。
对于这个图我们先选到这一条边
然后我们找到下一个点,发现它连接的一条边的终点已经被选中了,所以我们试着让第一个点重新匹配一个没有被匹配过的节点
然后我们找到第三个节点,发现可以匹配。
当我们找到第四个节点时,发现它所对应的节点没有办法修改匹配,至此匈牙利算法结束,最大匹配为3
而在我们进行匈牙利算法的时候有一些优化可以实现,比如如果一个点已经尝试匹配过,而且失败了,那么我们就不要尝试匹配了。(类似dfs减枝)
下面贴上算法
bool match(int u){
S[u]=;
for(int i=head[u];i;i=g[i].next)
if(!T[g[i].to]){
T[g[i].to]=;
if(!lky[g[i].to]||match(lky[g[i].to])){
lky[g[i].to]=u;lkx[u]=g[i].to;return true;
}
}
return false;
}
注:现在起所有的算法如果我没有写例题我都只会列出核心代码,剩下的东西请视情况补充。QAQ
培训补坑(day4:网络流建模与二分图匹配)的更多相关文章
- 培训补坑(day3:网络流&最小割)
继续补坑.. 第三天主要是网络流 首先我们先了解一下网络流的最基本的算法:dinic 这个算法的主要做法就是这样的: 在建好的网络流的图上从源点开始向汇点跑一遍BFS,然后如果一条边的流量不为0,那么 ...
- 培训补坑(day1:最短路&two-sat)
经过12天的滚粗,终于迎来了暑期培训的结尾啦QAQ 结业考才考了90分,真是对不起孙爷(孙爷请收下我的膝盖) orz小粉兔怒D rank 1 获得小粉兔一只QAQ 由于这次12天的培训题目又比较多,算 ...
- 培训补坑(day8:树上倍增+树链剖分)
补坑补坑.. 其实挺不理解孙爷为什么把这两个东西放在一起讲..当时我学这一块数据结构都学了一周左右吧(超虚的) 也许孙爷以为我们是省队集训班... 好吧,虽然如此,我还是会认真写博客(保证初学者不会出 ...
- 培训补坑(day7:线段树的区间修改与运用)(day6是测试,测试题解以后补坑QAQ)
补坑咯~ 今天围绕的是一个神奇的数据结构:线段树.(感觉叫做区间树也挺科学的.) 线段树,顾名思义就是用来查找一段区间内的最大值,最小值,区间和等等元素. 那么这个线段树有什么优势呢? 比如我们要多次 ...
- 培训补坑(day5:最小生成树+负环判断+差分约束)
补坑补坑((╯‵□′)╯︵┻━┻) 内容真的多... 一个一个来吧. 首先是最小生成树. 先讲一下生成树的定义 生成树就是在一张图上选取一些边,使得整个图上所有的点都连通. 那么我们要求的最小生成树有 ...
- 培训补坑(day2:割点与桥+强联通分量)
补坑ing... 好吧,这是第二天. 这一天我们主要围绕的就是一个人:tarjan......创造的强联通分量算法 对于这一天的内容我不按照顺序来讲,我们先讲一讲强联通分量,然后再讲割点与桥会便于理解 ...
- 培训补坑(day10:双指针扫描+矩阵快速幂)
这是一个神奇的课题,其实我觉得用一个词来形容这个算法挺合适的:暴力. 是啊,就是循环+暴力.没什么难的... 先来看一道裸题. 那么对于这道题,显然我们的暴力算法就是枚举区间的左右端点,然后通过前缀和 ...
- Codeforces Round #548 (Div. 2) E 二分图匹配(新坑) or 网络流 + 反向处理
https://codeforces.com/contest/1139/problem/E 题意 有n个学生,m个社团,每个学生有一个\(p_i\)值,然后每个学生属于\(c_i\)社团, 有d天,每 ...
- POJ2584 T-Shirt Gumbo 二分图匹配(网络流)
#include <cstdio> #include <cstring> #include <algorithm> const int inf=0x3f3f3f3f ...
随机推荐
- 如何删除hive表格的分区
今天的一个业务场景就是要把三年的数据从第一天不停的融合起来,每一天作为表格一个新的分区.由于空间有限,数据量很大,可能每天数据都是几十个G的大小.所以我需要做的一点就是在融合这一天之后,删除一天的分区 ...
- HTTP 响应时发生错误。这可能是由于服务终结点绑定未使用 HTTP 协议造成的。这还可能是由于服务器中止了 HTTP 请求上下文(可能由于服务关闭)所致。
第一种:无法序列化 DataTable.未设置 DataTable 名称. 第二种: 排除过程如下: 1.用WCF调试状态下的客户端调用ESB的Publish方法调用成功,证明ESB的推送是没有问题的 ...
- Pandas 数值计算和统计基础
1.(1) # 基本参数:axis.skipna import numpy as np import pandas as pd df = pd.DataFrame({'key1':[4,5,3,np. ...
- Android学习记录(2)—Android中数据库的常见操作
android中数据库操作是非常常见了,我们会经常用到,操作的方法也有很多种形式,这里我就把最常见的两种形式记录下来了,以备以后用到方便查看.我就不写注释和解释了,因为android数据库的操作和其它 ...
- 对setTimeout函数的理解
之前去面试一家公司时,面试官出了一道关于js的setTimeout函数的题目: /* *面试官给的原题目如下: *执行mytest()后,控制台输出内容是_____ *function mytest( ...
- 《Cracking the Coding Interview》——第4章:树和图——题目4
2014-03-19 03:40 题目:给定一棵二叉树,把每一层的节点串成一个链表,最终返回一个链表数组. 解法:前序遍历,遍历的同时向各个链表里添加节点.水平遍历好像还不如前序遍历来得方便. 代码: ...
- 更新域名解析以后,IP在cmd中ping不正确,清理DNS缓存
1清除ARP缓存,cmd下使用命令arp -d*代替执行. 2清除NETBT,cmd下使用命令nbtstat -R代替执行. 再清除DNS缓存,cmd下使用命令ipconfig /flushdns代替 ...
- 1079 Total Sales of Supply Chain (25 分)(树的遍历)
给出一颗销售供应的树,树根唯一.在树根处货物的价格为p,然后从根节点开始没往结点走一层,该层的货物价格将会在父节点的价格上增加r%.给出每个叶节点的货物量求出他们的价格之和 #include<b ...
- android瀑布流照片墙实现代码详解
照片墙的实现,是需要往手机里面添加很多图片的,如果没有对资源进行合理的释放,程序很快就会出现OOM.所以需要用到LruCache算法来缓存图片. 1,首先是图片资源类,这个类中包含了很多图片链接. p ...
- 启动Tomcat时的常见问题及解决办法
问题一:环境变量 1.检查jdk 验证jdk的配置,在运行-cmd中输入 java -version 即表示安装成功. 如果jdk没有问题,还需要配置两个环境变量.找到jdk和jre的路径,配置JAV ...