一、最短路
1.再谈Floyed
洛谷P1119 灾后重建
题目描述
给出BB地区的村庄数NN,村庄编号从00到N-1N−1,和所有MM条公路的长度,公路是双向的。并给出第ii个村庄重建完成的时间t_i,你可以认为是同时开始重建并在第t_i天重建完成,并且在当天即可通车。若t_it为0则说明地震未对此地区造成损坏,一开始就可以通车。之后有Q个询问(x, y, t),对于每个询问你要回答在第t天,从村庄x到村庄y的最短路径长度为多少。如果无法找到从x村庄到y村庄的路径,经过若干个已重建完成的村庄,或者村庄x或村庄y在第t天仍未重建完成 ,则需要返回-1。
对于100%100%的数据,有N≤200,M<=N^2,Q≤50000,所有输入数据涉及整数均不超过100000。
本题与普通最短路问题最大的不同在于询问时动态的,故常用的dijstra,spfa不能支持,每次都要重算一遍,效率太低。那么,考虑Floyed,之前在学的时候以为没什么用,就按照模板写了一下,实际上,对于f[i][j]=min(f[i][j],f[i][k]+f[k][j])这个式子,本质上是求前k个点更新过的最短路,只是把k那维压掉而已。再回到题目,发现题目条件与Floyed的过程恰好吻合,即每多一个点可用,就用它去更新,那么就可高效动态维护了。
本题告诉我们理解算法的思路还是很重要的,不能只背板子,其实很多题目的思维与其所用算法思维有很大的联系。
2、最短路模型的转换
ssoj3992: 新的世界(neworld)
题目描述
在一个N行M列的网格中,第i行j列的格子有一个可变的“亮度” Li,j(初始时都为0)和一个固定的“不透光度”Aij。现在在r行c列放入一个亮度为l的光源,NEWorld游戏引擎会根据以下逻辑,让光源逐步“照亮”附近的方格:
先将光源所在方格的亮度Lrc赋值为l。而对于i行j列一个不是光源的方格,它的亮度由Aij和四周方格的亮度所确定。定义F(i,j)=max{Li−1,j,Li+1,j
,Li,j−1,Li,j+1,Aij}−Aij(此处当1≤i′≤N不成立或1≤j′≤M不成立时,Li′j′Li′j′被看作是0),我们称方格(i,j)的亮度Lij是“有效”的,当且仅当Lij=F(i,j)。显然初始时所有亮度都是“有效”的,而放入光源后则可能存在亮度“无效”的方格。
现在引擎会循环执行操作,每一步找出当前所有亮度“无效”(不包括光源)的方格中,行数i最小的那一个(如果有多个行数i最小的,就选择其中列数j最小的方格),然后计算F(i,j)的值,将其赋值给Lij。操作会不停地执行,直到所有亮度都“有效”为止(请参考样例,循环一定会在有限步操作后结束)。请问最后p行q列的方格亮度值Lpq是多少?
n,m<=500
考场时由于这是T1,就没多想,直接大力模拟,结果TLE到只剩30分。其实,仔细分析题目,会发现题目所进行的操作类似于spfa的松弛操作,比较诡异的是max中多了个Ai,j,其实,我们可以将它看做强制答案非负的操作,就不用管它了。那么,题目的操作相当于每个点被周围的四个点连一条朝向它,长度为-Ai,j的边,求(c,r)到每个点的最长路,边权取反后,即为(r,c)到每个点的最短路的相反数,加上l,与0取max。由于是网格图,spfa会被卡,故用dij+堆。
二、欧拉回路
ssoj1117: 无序字母对 character
题目描述
给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒)。请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现。
题解:
要使相邻的无序字母对出现,可以抽象为经过一条走过这两个点的边,那么,将每个字母抽象为一个点,将字母对之间连无向边,则要经过所有边,就是求一条欧拉路径。
求欧拉路径的方法为:先判断,欧拉路径存在当且仅当度数为奇数的点位0或2个,存在时,找一个正确的起点,dfs一遍,走到走过的边就不走(为满足欧拉路径的要求),每个点直到没有路可走时就加入栈中(说明所有边都走完,形成欧拉路径),答案路径即从栈顶到栈底的点。
三、差分约束
1.ssoj1750: 小K 的农场(farm)
小K 是个特么喜欢玩MC 的孩纸。。。
小K 在MC 里面建立很多很多的农场,总共n 个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共m 个),以下列三种形式描述:
农场a 比农场b 至少多种植了c 个单位的作物,农场a 比农场b 至多多种植了c 个单位的作物,农场a 与农场b 种植的作物数一样多。但是,由于小K 的记忆有些偏差,所以他想要知道存不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合。
题解:
差分约束模板题,按照题意建边即可。
- 3401: 收银员(cashier)
秀秀家的超市是24小时营业的,现在需要招聘收银员。
超市每个小时都需要不同数量的收银员,用ai表示一天中i点到i+1点这一小时内需要的收银员数量,特别地a23表示23到次日0点需要的收银员数量。每个时刻可以有多于ai位收银员在工作,但是如果少于ai位收银员工作,就会忙不过来造成混乱。现在有n个人来应聘秀秀家的收银员,每个人愿意从一个特定的整点开始连续工作8小时。
秀秀想知道若所有人都能胜任这一职位,最少需要招多少人。若不存在符合要求的方案,请输出−1。
题解:
个人觉得这是一道思维很妙但代码很丑的题(为什么要弄个24啊。。。实在不舒服)。
题目给出了两个主要条件:第i天到i+1天的工作人数>=a[i]及第i天开始工作的人数<=b[i],要求的是最小工作人数。最小工作人数,对应到第二个条件中就是24小时开始的工作人数总和,那么也要对应到第一个条件中,即为前i天与前i-8天开始工作人数总和之差。发现前缀和组成了差分约束系统,但要求最小工作人数怎么办呢?因为是一个环,故不能直接等于最后一小时的最值。那退一步想,能不能已知工作人数上限,判断是否可行?又发现答案具有单调性,故可二分一个mid,这样又要多一个限制,即最后一小时与第0小时的差<=mid。注意还要考虑前缀和的不降性。
四、二分图匹配——匈牙利算法
其实这就是一种暴力+贪心的思想,对于左边的每一个点,依次遍历右边每一个与它相连的节点,若这个节点未被匹配,就匹配,否则就则尝试"反悔",看能不能再这个点不被匹配的情况下满足前面右边的点都被匹配,如果可以就反悔,然后匹配。这样一定最优,因为它保证了前i个点能匹配的匹配完后,给后面的点留下最多机会。
五、强连通分量——tarjan算法
将图转化为树来看就容易理解了,对于一个点,如果它的后代最多只能到达自己,那么这个点与其还未形成强连通分量的孩子就一定单独形成强连通分量;否则他所在的强连通分量一定包含它的祖先,因为它与它的某个祖先是强连通的。
同理,我们可以用此来求出无向图的割点、桥,然后不经过割点的极大联通图即为点双,不经过桥的即为边双。