最短路应用复习
最短路应用复习笔记
最短路树
比较简单,主要可用于判断某边或者某点是否在最短路上
方法是从开始点dj一次,从末尾也dj一次,然后利用等式关系判断即可
同余最短路
这个算是我很不理解的一个吧
说是实际上是对完全背包的一种优化(优化空间)
基本上就是这个模板:给出若干个数,每个数的个数有无限个,求这些数加起来可以由多少个不同的数(sums/莫莫的不等式这些题)
注意点:0的情况
用这一道题来说明比较简单:https://www.luogu.com.cn/problem/P3403
假设 a<b<c ,则对于每一个 i∈[1,n] ,都可以表示成 i=ax+k,其中,a 是除数,x 是商,k 是余数。
当k不等于0时,必须要使用b,c这两个才能凑出来。
同时,这个余数我也可以只通过b,c的累加就凑出来
假设此时我余数已经凑出来一个i了,那么我要是累加一个b能到j余数时,就存在(i+b)%a=j
此时,抽象一下,就可以说是从余数i到j有一个长度为b的边
那么,在这个图上跑最短路到k,就表示得到余数k的最短路径。
但是我用的%数来表示,在一个%数下可能存在很多个满足的数
这个数就是:
ans=∑(k=0~a−1) (h−disk)/a +1(h是枚举上界)
为什么是这个公式呢:首先,我跑了最短路,那么,disk肯定是凑出一个最小的数x满足x%a=k.
用h-disk表示剩下的区间,这剩下的区间中,我不断加a,还是能保证moda=k数不变,而我加的次数就是(h-disk)/a;
加1则是加上本身这一次
然后我把所有可能的mod数的所有情况加起来就是整体的答案了!
AC重要代码:https://www.luogu.com.cn/record/116659804
弄懂就好了!
void dj(int s){
memset(dis, 0x3f3f, sizeof dis);
dis[s%x]=1;
q.push((pr){1,s});
while(q.size()){
pr tmp=q.top();
q.pop();
int u=tmp.id;
if(!vis[u]){
vis[u]=1;
int to1=(u+y)%x;
int to2=(u+z)%x;
if(dis[to1]>dis[u]+y){
dis[to1]=dis[u]+y;
q.push((pr){dis[to1],to1});
}
if(dis[to2]>dis[u]+z){
dis[to2]=dis[u]+z;
q.push((pr){dis[to2],to2});
}
}
}
}
差分约束
具体在另一篇博客有说,点击跳转:https://www.cnblogs.com/linghusama/p/17542288.html