这一周我们学习了最短路径和最小生成树,相较于上一周其实还是套模板的居多,不过是最短路的方法有好几个,大致有三个分别是dijkstra spfa 和floyd,这些方法的使用还是比较好区分的,而且spfa大部分用不到,而且比较容易被卡数据,大部分都是dijkstra和floyd用来解决
先说floyd,floyd的题型一般就是求任意两个结点的最短路,也就是枚举中间结点k看看是直连的路径短还是通过中间节点的路径最短。
如下:
for(int k=1;k<=n;k++){
for(int j=1;j<=n;j++){
for(int i=1;i<=n;i++){
if(i==j||i==k||j==k) continue;
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);//双向
f[j][i]=min(f[j][i],f[j][k]+f[k][i]);
}
}
}
举个floyd模板题:P3906 Geodetic集合 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
因为是三重循环所以复杂度还是挺高的基本上n的取值不能太高,因为是循环全都记录一遍,可以用来求任意的两个点间最短距,也可以求固定单点对的最短路,所以假如n在不高的前提下,当求固定点时可以考虑floyd暴力通过
接着是dijkstra算法,大部分题目用dj算法还是挺管用的,dj的题目也表示的比较明确就是单源最短路径,即固定点s,求点s到达其他点的最短距离
比如:
P1744 采购特价商品 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
就是给出所有点的道路信息,求给定点s到t的最短路,一般dj都用堆来进行优化
void dj()
{
for(int i=1;i<=n;++i)
{//初始化
}
q.push(M(0,s));//进堆
dis[s]=0;
vis[s]=1;
while (l.size()) //dj主体
{
k=l.top();l.pop();j=k.key; //取堆顶
if (f[j])continue;f[j]=1;
for (i=1;i<=n;i++) //dj核心
if (r[j][i] && d[j]+r[j][i]<d[i])
{
d[i]=d[j]+r[j][i]; //更新d
l.push((heap){d[i],i}); //进堆
}
}
}
这些都是比较正常的dj最短路径题,还有些就要反复利用dj单源的特点
如:P1821 [USACO07FEB] Cow Party S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目描述
寒假到了,n 头牛都要去参加一场在编号为 x的牛的农场举行的派对,农场之间有 m 条有向路,每条路都有一定的长度。
每头牛参加完派对后都必须回家,无论是去参加派对还是回家,每头牛都会选择最短路径,求这 n 头牛的最短路径(一个来回)中最长的一条路径长度。
这题难的地方在于,这是有向边而且需要来回两趟的最短路,去的时候是单终点,回的时候是单源点,所以我们可以在去的时候反向存边用dj,把单终点转化为单源最短路的问题上,回的时候直接正向用dj就行,这样用两次dj就结束了,关键还是怎么看待问题,反向建边也并不是唯一的解决方法
总结:
总的来说这周的收获还是挺大的,而且但从题目来说,基本上是套模板解决问题,而关键就在于给你工具怎么去使用,而且这周的题目相对来说要容易不少,但毕竟其实接触的也不长,而且时间也很紧,对于这些新知识,可能当时记得挺好的吗,但是一过几天也就记得不是很清楚了,所以学算法不能死记硬背代码,这是行不通的,要学会抽象出模型来,我写代码最大的感触就是,我经常在想如何记住某某代码,如何在考场上迅速的写出来,除了平时的练习以外,我觉得最好的并不是死记硬背,写代码就像制作一个工艺品,每个工艺品确实有相应的工序,但是更多的是在进行这些工序时如何加入自己的理解,一开始不理解不要紧,先化为自己的理解,等慢慢练习后就会熟悉,就会明白是什么原因了,这样每件工艺品加入自己的理解后你自己也就会慢慢记住,比如把大象放进冰箱需要几步,一开始不了解不要紧可以先记住需要几步,然后反复练习反复琢磨为什么这一步要这样而不是那样,结果是什么,有什么好处,慢慢就会抽象出一个模型,一个适用于相应动作的模型,不仅仅是放大象,还可以放水果,放饮料等等。虽然我还是什么都不懂,但是并不妨碍我知道,我了解,希望下次能更合理的安排时间,提高效率