最短路应用复习

最短路应用复习笔记

最短路树

比较简单,主要可用于判断某边或者某点是否在最短路上
方法是从开始点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

posted @ 2023-07-20 22:41  铃狐sama  阅读(9)  评论(0)    收藏  举报