图论算法与模型(训练指南题库)

一、基础题目

1、UVA 11624 Fire!迷宫问题 多源BFS

题意:

帮助joe走出一个大火蔓延的迷宫,其中joe每分钟可往上下左右四个方向之一走,所有着火的格子都会蔓延(空格与着火格有公共边,下一分钟这个空格也会着火)。迷宫中有一些障碍格,joe和火都无法进入,当joe走到一个边界的格子我们认为他走出了迷宫

输出R行C列的迷宫,#表示墙,.表示空地,J表示joe,F是着火格

如果能走出,输出最少时间否则,impossible

思路:

先预处理出每个点的起火时间,可以用多源点BFS直接处理出来

再用BFS求从出发点到边界的最短路,每次扩展点的时候保证走到该点的时间严格小于该点起火时间

代码:

https://paste.ubuntu.com/p/R4bpSJDGvP/

 

 

2、UVA 10047 The Monocycle 迷宫问题 复合状态

 题意:

从起点到终点,每秒可以选择前进、向左、向右转, 每前进一格轮子转到下一个颜色, 一共5种颜色, 开始的时候绿色接触地面,朝北, 要求最后也绿色接触地面,求能否到达目标点以及最短时间。

思路:

BFS 多了两维状态 直接模拟即可

代码:

https://paste.ubuntu.com/p/QRDxqFxN6F/

 

3、UVA 10054 The Necklace 欧拉回路

题意:

n个珠子,每个珠子的两半由不同的颜色组成。 只有相同的颜色才能接在一起, 问能否组成一个一个项链。

思路:

判断每个点的度数均为偶数个,判断图联通,注意有重边。然后用刘汝佳的欧拉回路模板即可。

代码:

https://paste.ubuntu.com/p/9VPsbRh53M/

 

4、UVALive 4255 Guess 拓扑排序

题意:

对于一个序列a1,a2,a3,….an,我们可以计算出一个符号矩阵S,就是上面右图矩阵,其中S(i,j)表示 ai+…+aj的正负号,给出序列不难求出矩阵,我们的任务是求出“逆问题”,即给出矩阵,求出序列,序列每个值大于-10小于10;

思路:

拓扑排序即可,主意需要用Kahn算法进行拓扑排序,因为有多个入度为0的点的话,必须设置成权值一样的点。

 代码:

https://paste.ubuntu.com/p/VwF7NcWZnx/

 

二、DFS的应用

二分图判定 无向图割顶和桥 无向图双连通分量 有向图强连通分量 2-SAT问题

1、UVAlive 3523 Knights of the Round Table 二分图+双连通分量

题意:

n(n1000)个骑士,m(m1000000)对骑士互相憎恨,要3个以上的骑士且保证互相憎恨的骑士不会坐在相邻位置才能开会议,求多少骑士一定不能参加任何一次会议。

思路:

首先建图,两个骑士可以相邻,那么就连边。那么题目转化成求不在任何一个简单奇圈上的节点的个数。如果图G不连通,那么分成几个连通分量来求解。

假设图G连通,那么简单圈上的点必然属于一个双连通分量,所以先找出所有双连通分量。

二分图的充要条件是没有奇圈,可以很明显的得到:如果一个双连通分量是二分图,那么里面的点一定不在奇圈上。

如果一个双连通分量不是二分图,那么里面的点会在奇圈上吗?

答案是一定在奇圈上,首先双连通分量不是二分图,那么里面一定存在一个奇圈C。对于这个连通分量里面的点,有两种状态,在C上和不在C上。

在C上的话,本身C就是一个奇圈

不在C上的话,可以构造出一个奇圈出来。在C上取两点u1和u2,u1到u2有两条不相交路径,并且长度为一奇一偶,对于C外的任意一点v,由于是在双连通分量内,v到u1,v到u2有不相交的两条路径,这样的话,由于u1到u2之间既有偶数长度的路径,也有奇数长度的路径,所以v一定可以和u1 u2构造出奇圈出来。

 

整理一下思路就是首先求出所有的双连通分量,再判断这个双连通分量是不是二分图,如果不是二分图,那么该连通分量里面的点都为可以在奇圈的点,处理出所有可以在奇圈上的点之后,再算出不可以在奇圈上的点的数目即可。

代码:

https://paste.ubuntu.com/p/KjYRQ2rDwR/

 

2、UVAlive 5135 Mining Your Own Business 双连通分量 割顶

题意:

一座地下稀有金属矿由n条隧道和一些连接点组成,每条隧道连接两点。任意两点之间最多一条隧道。你的任务是在一些连接点处安装逃生装置,使得不管哪个连接点倒塌,不在此连接点的所有矿工都能到达太平井逃生。为了节约成本,你应当在尽量少的连接点安装太平井。输出数目和方案数。

思路:

本题模型:在无向图上选择尽量少的点涂黑,使得任意删除一个点后每个连通分量至少有一个黑点。

可以这样想,如果删除点是割点,那么割点会把图分成几个连通分量,那么至少需要这么多个黑点。

最优策略是对于一个点-双连通分量中如果只有一个割点,那么这里面必须选一个染黑,染黑方法为除了割点之外的点任选一个即可。

特殊情况:只有一个双连通分量,此时一定没有割点,因为割点是至少两个不同双连通分量的公共点。那么任意染黑两个点即可。

代码:

https://paste.ubuntu.com/p/vVDvKv8XhS/

 

3、UVAlive 4287 Proving Equivalences 强连通分量 缩点

题意:

给出n个点,m条边,问最少添加多少条边,使得有向图为强连通

思路:

缩点,构成新图DAG,在新图上,入度为0的点数目为a,出度为0的点数目为b,ans = Max(a, b),特判,如果本来就是强连通的,那么ans = 0

代码:

https://paste.ubuntu.com/p/q2RTbKv26y/

 

4、UVA 11324 The Largest Clique 强连通分量 缩点  DP

题意:

给一张有向图G,求一个节点数最大的节点集合,使得该集合中任意两个点u和v满足,要么u可以到达v,要么v可以到达u。(u、v相互到达也可以)

思路:

最优解中,同一个强连通分量中的点,要么全选,要么全不选。所以可以缩点,构造出DAG图,图上每个点的价值为这个强连通分量里面的点的个数。然后用记忆化搜索求出最大权值的路径即可。

代码:

https://paste.ubuntu.com/p/YrpPGbpM46/

 

5、UVAlive 3211 Now or later 二分 2-SAT

题意:

n架飞机,每架可选择两个着落时间。安排一个着陆时间表,使得着陆间隔的最小值最大。

思路:

二分着陆间隔最小值,用2-SAT判定

对于i飞机的a状态和j飞机的b状态,如果他们之间的距离小于二分的值,说明不能满足二分的最小值,所以a状态和b状态不能同时存在,所以在2-SAT中添加i = !a  or j = !b的判定条件。

代码:

https://paste.ubuntu.com/p/BCjBNnwF85/

 

6、UVAlive 3713 Astronauts 2-sat

题意:

 

有A,B,C三个人物要分配个N个宇航员,每个宇航员恰好要分配一个任务,设平均年龄为X,只有年龄大于或等于X的宇航员才能分配任务A。只有年龄严格小于X的宇航员才能分配任务B。而任务C没有限制。有M对宇航员相互讨厌,因此不能分配到同一任务。编程找出一个满足上述所有要求的任务分配方案。

思路:

宇航员分成两类,一类做A(true)和C(false) 一类做B(true)和C(false)

如果两人互相憎恨,对于同类的宇航员,必须是1true 1false 用两个语句限制:xi or xj   !xi or !xj

对于一类的宇航员,只要不是都是C即可,那就是一个语句xi or xj

题目说输入m=0 n=0是结束,必须两个同时为0输入结束,一个为0不行。

代码:

https://paste.ubuntu.com/p/hd4TKHNTDB/ 

 

7、UVA 11396 Claw Decomposition 二分图判定

题意:

 

给出一个简单无向图,每个点的度为3。判断能否将此图分解成若干爪的形式,使得每条边都只出现在唯一的爪中。(点可以多次出现在爪中)

 

思路:

稍加推理可以知道,一个点如果是爪的那个"头",那么与他相邻的点不是"头",那么与这些不是头相邻的点一定是"头"。这就是二分图判定即可。

WA了几发因为数组没清空(无语.jpg,又开始这种低级错误了)

代码:

https://paste.ubuntu.com/p/wfNBmxB8yW/

 

8、UVAlive 3486 Cells dfs用栈模拟

题意:

给一棵树,每次每次询问一个点是否是另一个点的祖先?

思路:

题目的读入就有点坑爹,注意,每个节点的值是说明它下面有多少个儿子节点,直接对于每个下标保存一个值即可。

询问u是不是v的祖先,可以用时间戳,在开始dfs的时候和结束的时候打标机,如果u的开始标记小于v的开始标记,并且u的结束标记大于v的结束标记,那么u一定是v的祖先。

注意用栈模拟。

题目在每两个样例之间需要输出空行,多输出空行会判成WA

代码:

https://paste.ubuntu.com/p/g7sGXVr5jN/

 

9、UVA 10765 双连通分量

题意:

给定一个n个点的连通图,一个点的鸽子值定义为将他从图中删去后连通块的个数。求前m大鸽子值。

思路:

直接求双连通分量,如果一个点不是割点,那么只会在某一个双连通分量中出现一次,并且删去之后,连通块数目还是1。如果一个点是割点,删去之后分成k个连通块,说明这个点在k个双连通分量中出现过。所以直接统计双连通分量每个点出现次数即可。

代码:

https://paste.ubuntu.com/p/28sGwvDgdN/

 

10、UVA 11294 Wedding 2-SAT

题意:

n对夫妻参加婚礼,新郎和新娘是第0对夫妻,要求安排座位,新郎新娘不能坐同一侧,其余n-1对夫妻也不能让那个同侧,新娘只能看见对面坐的人,有m对有关系的人,她不想看见这同时看见两个有关系的人坐在对面。

思路:

这题也是2-SAT问题。首先设置新娘这一边为true,新郎这一边为false。需要初始化新娘在2-SAT内的mark数组中的2*i+1为true。

对于每一对夫妻不能同侧 那么可以 u or v 和 !u or !v两个语句表示。

对于有关系的两人不能在新娘的对面,也就是不能同为false 那么只需要语句 u or v表示即可。

注意输出的时候输出新娘这一侧坐的人,在开始的时候需要将新娘的true标记为1

代码:

https://paste.ubuntu.com/p/ZQ4YYj85nM/

 

11、UVAlive 4452 The Ministers' Major Mess 2-SAT模型的建立

题意:

n个人对m个方案进行投票,每个人最多对m个方案中的4个投票,要么支持,要么反对,问是否存在最终决定,能够让每个投票人都有一半以上的建议被采纳。

在所有的最终决定中,那些方案的态度是可以却确定的?

注:一半以上,也就是当一个人投票数目<=2时,他提出的建议必须全部接受,数目为3 4时,至多只有一个建议不接受

思路:

对于投票数目小于等于2的,直接用2-SAT的标记数组,标记这个建议为true还是false。(检查是不是会有同时标记true和false的)

对于投票数目大于等于3的,至多一个不接受,也就是当一个不接受是,其他的必须接受。

这就回到了2-SAT的建图基础,2-SAT建图是建立析取式转化成两个蕴含式,u or v 等价于 !u ->v 和 !v->u 建图的时候也是G[u^1].push_back(v)和G[v^1].push_back(u)

现在直接告诉你蕴含式,所以可以直接建图。

对于一个人提出的建议u,如果u不成立,那么他提出的其他所有的建议必须接受,也就是!u->v

建好了图之后,就可以找是不是存在解,但并不是单纯的判断是不是有解,而是询问在所有解中,哪些方案的态度可以确定?

也就是在所有的解中,哪些方案永远是true,哪些永远是false

只需要在模板的solve函数中添加dfs(i)和dfs(i+1)

判断对于第i/2个方案而言,为true和为false是否有解,如果都有解,那就将标记清空,如果只有true有解,只记录为true,如果只有false有解,只记录为false,如果都无解,返回假。

代码:

https://paste.ubuntu.com/p/GwMtpYXBt6/

 

12、UVA 10972  RevolC FaeLoN 边-双连通分量

题意:

给一个无向图,要求将所有边改为有向边,求还需要添加多少有向边才能使其强连通。

思路:

一开始想的是寻找点-双连通分量,然后发现想错了,应该是求出边-双连通分量,因为边双连通分量就可以改成有向图的强连通分量。

缩点之后记录度数为0的点数目a和度数为1的点数目b。答案是a+(b+1)/2,因为一条边可以连接两个度数为1的点,使他们连通,一条边只能连一个度数为1的点,使其加入一个环中,构成强连通图。

代码:

https://paste.ubuntu.com/p/N87qGw6h77/

 

三、最短路的应用

Dijkstra Bellm-Ford SPFA Floyd

1、UVA 11374 Dijkstra 预处理 枚举

题意:

有两种车票,商务车票和经济车票。由于经济原因,商务车票只能买一张,经济车票可以买多张。车票都是双向的。现在问从起点到终点,的最短路径,以及商务车票在哪个站点用最划算和最后花费的总时间。

思路:

因为商务车票只能买一张,所以可以枚举到底买哪一张,如果可以在O(1)时间内计算出每种方案的最优解,那么整体时间复杂度在O(K),K为商务车票数目。

假设我们选择的商务车票a到b,那么从起点到a,从b到终点的时间求出来即可。也就是跑两个单源最短路径,预处理出从起点出发到各点的路径长度,和从各点到终点的路径长度。由于是双向边,从各个点到终点的最短路等价于从终点到各点的最短路。

代码:

https://paste.ubuntu.com/p/DzCj6s5drn/

 

2、UVA 10917 最短路树 DP 记忆化搜索

题意:

gbn最近打算穿过一个森林,但是他比较傲娇,于是他决定只走一些特殊的道路,他打算只沿着满足如下条件的(A,B)道路走:存在一条从B出发回家的路,比所有从A出发回家的路径都短。你的任务是计算一共有多少条不同的回家路径。其中起点的编号为1,终点的编号为2. 

思路:

存在一条从B出发回家的路,比所有从A出发回家的路径都短。等价于从B到终点的最短路d[B]小于从A到终点的最短路d[A]。

这样预处理d数组,然后dfs从起点到终点,每次走只有d[B] < d[A]才有有向边A->B。这是一个DAG图,可以用记忆化搜索记录路径条数

代码:

https://paste.ubuntu.com/p/X9Kj6p2vGf/

 

3、UVAlive 4080 最短路树 

题意:

给N个点,M条边,如果两个点之间没有边,则默认为l。问所有点两两之间最短路之和是多少。然后删除一条边,问删除某一条边后最大是多少。

思路:

如果用floyd算法,需要算M次,时间复杂度为O(n3m),很难承受,如果对每个点进行m次Dijkstra,那么总共需要进行n*m次dijkstra算法,时间复杂度为O(nm2logn),还是很大。

这时最短路树派上用场,对于单源最短路径,只有删除最短路树上的这n-1条边,单源点最短路才会发生改变,这样对于每个点只需要删除这n-1条边,每个点dijkstra次数为n次,时间复杂度为O(n2mlogn),根据数据范围可以接受。

代码:

https://paste.ubuntu.com/p/QQVS3pg96M/

 

4、UVA 10537 逆向Dijkstra 字典序

题意:

有两种节点,一种是大写字母,一种是小写字母,当时小写字母是要付1各单位的过路费,当时大写字母的时候要付当前自己财务的1/20分之一(向上取整)当做过路费。求最少带多少个物品从起点到终点能在最后交付的时候有k个物品。

坑点:从u->v,收取v点的路费

思路:

用dijkstra的思想逆推,d[i]表示到达i点至少需要的货物,每次取出d值最小的进行dijkstra算法。求出最短路后,正向推出字典序最小的解。

代码:

https://paste.ubuntu.com/p/R5qnGNk4mW/

 

5、UVA 11090 二分 bellman-ford

题意:

给定一个n个点m条边的加权有向图,求平均权值最小的回路。

思路:

二分最小平均权值,对于每条边减去这个二分值m,如果图中出现负环,那么说明最小平均权值小于等于m,否则大于m。

注意:需要先判断减去最大值+1后是否会出现负环,如果不出现说明没有环。

图不是联通的!!!!,判断是否存在负环的时候需要每个点判断一遍。

代码:

https://paste.ubuntu.com/p/JjjXCxNVDF/

 

6、UVA 11478 差分约束系统

题意:

思路:

代码:

 

7、UVAlive 4128 状态图设计 dijkstra

题意:

思路:

代码:

 

8、UVAlive 3561 状态图设计 dijkstra

题意:

思路:

代码:

 

9、UVAlive 3661 平面图的最小割 对偶图

题意:

思路:

代码:

 

posted @ 2018-09-05 21:52  _努力努力再努力x  阅读(826)  评论(0编辑  收藏  举报