图论最短路模板总结

  • 之前写了一个动规背包模板,这回进军图论最短路。

最短路算法

  • 以下默认w[x][y]为连接x,y的边的长度。

Floyd

  • 说实话我真的不知道要不要加e了,就这样吧
  • 最简单的一种,三层循环结束,超级好记
  • 当然,时间复杂度为O(N^3),建议n不超过200
设f[x][y]为x到y的最短路径的长度.
注:初始化 x,y有边相连f[x][y]=w[x][y],否则f[x][y]=0x3fffffff.
(也就是尽量大,不是0x7fffffff保证int不爆.for(int k=1;k<=n;k++)
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
  • 它的大体思想是以k作为中转站,逐步更新。
  • 注意k的循环要在最外层,保证不会漏点。

Dijkastra

  • 计算某一点到其他点的最短路径,时间复杂度O(N^2)。
  • 注意Dijkastra不能处理负边权。
  • 大致流程为初始化——找顶点——标记,更新
设起点为s,f[x]表示s到x的最短距离,用bool类型的flag数组标记是否已确定(即书上的“染色”).
for(int i=1;i<=n;i++)//初始化 
	f[i]=w[s][i];
f[s]=0,flag[s]=1;
for(int i=1;i<=n;i++){
	int m=0x3fffffff,k;//记录最小值 
	for(int j=1;j<=n;j++)
		if(!flag[j]&&f[j]<m)
			m=f[j],k=j;
	flag[k]=1;//标记 
	for(int j=1;j<=n;j++)//更新 
		if(!flag[j]&&f[k]+w[k][j]<f[j])
			f[j]=f[k]+w[k][j];
}

SPFA

  • SPFA和广搜有一点点像,区别就在于SPFA中每个点可以重复入,但广搜不能。
设f[x]记录从s到x的最短距离,bool类数组flag记录该点是否在队列中.
queue<int> q;
for(int i=1;i<=n;i++)//预处理
		f[i]=w[s][i];
	q.push(s);flag[s]=1;//起点入队 
	while(!q.empty()){
		int x=q.front();q.pop();
		flag[x]=0;//取消标记 
		for 枚举与x相连的所有点i //不能全部枚举,会超时 
			if(f[i]>f[x]+w[i][x]){
				f[i]=f[x]+w[i][x];//更新 
				if(!flag[i]){//更新后入队
					q.push(i);
					flag[i]=1;
				} 
			}
	}

数据结构

  • 就两个,没办法,我就会这俩。

链式前向星

  • 有点好用,就是好久不用忘了点。
int n,m,k;//n个点,m条边 
int h[maxn]//maxn为点数最大值 
struct node{
	int w,to,next; //w边权;to终点;next该起点的下一条边 
}f[maxn];
void add(int u,int v,int w){//起点,终点,边权 
	k++;
	f[k].to=v,f[k].w=w,f[k].next=h[u];//记录终点,边权,该起点的下一个点的编号 
	h[u]=k;//更新h数组,记录该点 
}
//加边示例:add(u,v,w);(u起点,v终点,w边权)
//双向边示例:add(u,v,w);add(v,u,w);(同上)
void init(){
	for(int i=1;i<=n;i++)
		h[i]=-1;
	k=0;
}
void paint(){
	for(int i=1;i<=n;i++){
		for(int j=h[i];j!=-1;j=f[j].next)
			cout<<i<<" "<<f[i].to<<" "<<f[i].w<<endl;
		cout<<endl;
	}		
}

邻接表

  • 结构如其名,用表存储点与点的距离,例如以上的Floyd就采用了邻接表。(希望小蒟蒻没写错)
  • 这个模块就是来凑数的,没什么好说的。
  • 主要是有点排版强迫症,把链式前向星和其他的排一起怪怪的。

完成撒花!

  • 欧耶!我写完了!!!
  • 历时一周的大作(并没有)
  • 感想:拖延症真可怕
  • 但我下次还敢拖 (此作者已被拉走(不要拖延啊这是教训)(bushi))
  • 总之,最后皮一下真的很开心
  • FIN.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值