POJ 1274 The Perfect Stall

题意

求二分图最大匹配。

思路

教学题,只要使用了二分图/网络流就可以通过。在这里我强行使用了Hopcroft-Karp Algorithm,因为看了很长时间自己也很难理解,决定抄一遍别人的代码仔细领悟。核心部分我加了好多注释帮助理解。

代码

 

POJ3352 Road Construction / POJ3177 Redundant Paths

题意

给你一个联通图,问你最少要添加多少条边才能把这个图变成一个双联通图。

思路

非常经典的边双联通分量缩点问题。找出图中所有的边双联通分量,把这些分量各自收缩为一个点,节点之间若有边,一定是割边,这样就得到了一棵由边联通分量缩成的点和割边组成的树,把一个树变成双联通图要添加的最少边数是(r+1)/2其中r是这棵树的节点数量,这是一个蛮重要的结论。

找边联通分量的方法有好多,可以找到所有割边之后,对于每个点启动一次dfs,搜索中屏蔽掉所有割边,这样就可以收割所有的边双联通分量,也可以对于每个点直接启动一次tarjan算法,在函数返回的过程中,收割掉所有low值一样的节点就可以得到边双联通分量。这份代码使用的是后一种方案。

代码

两个题一个数据中有重边,一个没有,这份代码考虑了这个问题,所以连边都能顺利过,双倍经验。

 

HDU4738 Caocao's Bridges

题意

给出一个图,和一堆边,不保证没有重边,每一个边上携带者一个权值,现在问你能不能删去一条边,使图不再联通。可以的话删去权值最小的那条边,并且输出这个权值。

注意(坑点)

因为题意的特殊性,如果图本来就不联通,输出0.如果可以满足条件但最小的权值恰好是0,要输出1。

思路

删一个边把图裂开这种要求很明显就是找图的割边了。寻找割边是很典型的问题,应该使用tarjan算法,但是一定要注意重边对于找割边的影响(因为割边删掉后,图应该会裂开,但是如果有重边,删掉一条,还有一条,图显然不会裂开),因此我们要对原来的方法稍作修改,首先是存图的方式,我们不能漏掉任意一条边,因此一个理想的方式就是链式前向星。链式前向星有一个很好用的特性,我们在创建无向边的时候实际上是创建了两条有向边,而这两条有向边在链式前向星的容器中的编号是相邻的,也就是说对于编号i的边i^1就是这条边对应的反向边,这样我们就可以非常方便地标记这条边是不是已经走过(vis_e[i] = vis_e[i^1] = true)。tarjan部分附带了注释。

代码

 

SGU 101 Domino

题意

给你一堆骨牌,每张骨牌正反两面各有一个0~6范围内的数字,你要做的是确定一种骨牌的排列方式和骨牌的正反似的相邻的两个骨牌的面数字一样。

思路

这种链接多个物体,物体之间通过公共部分链接,这种题是可以转换成图论题做的。那么这个题应该怎么转换?
我们建立0~6这7个节点,每张骨牌就可以看作是链接骨牌上两个数的边,我们要做的就是找到一个路径使得我们可以“一笔”走过所有的边,其实这个叫欧拉通路。
关于欧拉通路,欧拉回路的更多细节,可以参看http://haha.school/guanyuoulahuiluheoulalujing/
找出欧拉回路的方法就是DFS,但是和以往不同的是我们把处理工作放在下一层返回之后做。同时本题还需要判断欧拉回路是否存在,如果不存在的话要输出无解。

代码

 

关于欧拉回路和欧拉路径

请留意本文转载自http://www.cppblog.com/abilitytao/archive/2010/07/26/121319.html

如果侵犯了您(原作者)的权益请联系我删除,谢谢。

定义:
欧拉回路:每条边恰好只走一次,并能回到出发点的路径
欧拉路径:经过每一条边一次,但是不要求回到起始点

①首先看欧拉回路存在性的判定:

一、无向图
每个顶点的度数都是偶数,则存在欧拉回路。

二、有向图(所有边都是单向的)
每个节顶点的入度都等于出度,则存在欧拉回路。

三.混合图欧拉回路
混合图欧拉回路用的是网络流。
把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。
好了,现在每个点入度和出度之差均为偶数。那么将这个偶数除以2,得x。也就是说,对于每一个点,只要将x条边改变方向(入>出就是变入,出>入就是变出),就能保证出 = 入。如果每个点都是出 = 入,那么很明显,该图就存在欧拉回路。
现在的问题就变成了:我该改变哪些边,可以让每个点出 = 入?构造网络流模型。首先,有向边是不能改变方向的,要之无用,删。一开始不是把无向边定向了吗?定的是什么向,就把网络构建成什么样,边长容量上限1。另新建s和t。对于入 > 出的点u,连接边(u, t)、容量为x,对于出 > 入的点v,连接边(s, v),容量为x(注意对不同的点x不同)。之后,察看是否有满流的分配。有就是能有欧拉回路,没有就是没有。欧拉回路是哪个?查看流值分配,将所有流量非 0(上限是1,流值不是0就是1)的边反向,就能得到每点入度 = 出度的欧拉图。
由于是满流,所以每个入 > 出的点,都有x条边进来,将这些进来的边反向,OK,入 = 出了。对于出 > 入的点亦然。那么,没和s、t连接的点怎么办?和s连接的条件是出 > 入,和t连接的条件是入 > 出,那么这个既没和s也没和t连接的点,自然早在开始就已经满足入 = 出了。那么在网络流过程中,这些点属于“中间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反向之后,自然仍保持平衡。
所以,就这样,混合图欧拉回路问题,解了。
②.欧拉路径存在性的判定

一。无向图
一个无向图存在欧拉路径,当且仅当   该图所有顶点的度数为偶数   或者  除了两个度数为奇数外其余的全是偶数

二。有向图
一个有向图存在欧拉路径,当且仅当 该图所有顶点的度数为零     或者 一个顶点的度数为1,另一个度数为-1,其他顶点的度数为0

三。混合图欧拉路径
其实整篇文章只有这部分是我写的哈,灰常不好意思,只是网上的同志们写的太好了,实在没有必要重复劳动,不知道大家有没有发现,求欧拉路径的第一步一定是求欧拉回路,在混合图上也不例外,如何判断混合图欧拉回路问题的存在性呢?首先,我们用上文所说的方法判断该图是否存在欧拉回路,如果存在,欧拉路径一定存在。如果欧拉回路不存在,那么我们枚举欧拉路径的起点和终点,连接一条无向边,然后再用最大流判断是否存在欧拉回路即可。

SGU 103 Traffic Lights

题意

http://www.nocow.cn/index.php/Translate:Sgu/103
翻译版,这里不重复劳动了

思路

这个题的可怕之处不是有多难想,而是虽然基本模型很简单就是图上最短路,但是这回有许多许多的限制条件。
正确地计算当前灯的状态是这个题最大的难点,我采用的方法是(其实我写跪了,李大神给我捞上来的):首先把到这个路口已经消耗的时间减去题目给的初始时间,我叫他有效时间,接下来把这个有效时间模上两种颜色的灯持续时间之和,剩下的时间是对灯的状态真正有影响的时间,接下来分别脑内模拟一下站在这个路灯时如果是紫色最后会怎么变,如果是蓝色会怎么变,然后基本就可以写出这个时间和最终颜色的关系了,还可以得到最终这个颜色还能再持续多长时间,这两条非常重要,一定要搞对。
接下来的难点就是计算从当前点移动到下一个点之前等待两点灯的颜色同步的时间,算这个就要依赖于上面的两个值:当前颜色和当前颜色还剩多长时间,假设我们要从A点移动到B,已经走了tim时间,那么我们就要分别计算A点和B点在tim时的这两个数据,然后如果AB在tim时颜色正好相等,那么无需等待直接通行,所以等待时间为0,如果颜色不同呢?只要看A和B哪个剩余的时间短,这个就是等待时间了。要是剩余的时间又一样?那就要脑内模拟一下了,然后发现我们可以再比较A的下一颜色和B的下一颜色谁的持续时间短,等待时间就是剩余时间+最短的持续时间。如果下一个颜色还一样,那就比较下下个颜色。要是还一样?对不起,hehe了,走别的吧~(所以说这个题很sxbk)
接下来是最段路部分,我们把权值设定为走到这个点要花多少时间,从当前点走到下一个点时,下一个点的可能值就是(当前点已用时间+等待两个点的灯同步的时间+路上消耗的时间),以此为基准进行松弛操作。

接下来上代码

 

CodeForces 475B Strongly Connected City

强联通分量的题,建图搞定了就搞定了。关于scc的算法可以翻我的图论标签找一下我写的一篇tarjan算法总结。

HDU 1142 A Walk Through the Forest

这个题数据好像有坑,如果用vector实现的邻接表会WAWAWA。。。嗯

然后题意那个sxbk的英语也是醉人,要是理解成最短路有多少条就哈哈了,应该是使到2节点的最短距离递减的节点序列有多少条。

然后你理解对了题意,又很脸好地用了邻接矩阵,嗯,估计还会T一阵子,原因是这个题还要卡DFS的优化问题,要使用记忆化搜索。

把这三点都注意了就能A了。(如果数据不坑,其实真是个好题)

HDU 1874 畅通工程续

这是个裸的最短路问题,随便怎么搞都行。

这里用的是没有堆优化的dijkstra。

POJ 1062 昂贵的聘礼

这个题是一个比较基准有些多的最短路(和之前那个Dirt挺像)。

(这里的cost就是dijkstra算法里面的dis值)每一次更新下一节点时,下一节点的cost值为(当前cost值-当前点权+下一边边权+下一点点权);每一次到达节点后,都根据当前抽出的节点的地位值,更新当前走过节点的地位的最大最小值,等接下来更新临接节点时,如果下一节点的地位与当前最大最小值中任意一个只差绝对值>m就要抛弃。以这两个为基准,进行正常的dijkstra,然后从头到尾的扫一遍cost数组,把最小值输出来就是答案。

Scroll to top