最短路问题

最短路问题我想分为3个环节来讲

1.Floyd
2.Dijkstra
3.SPFA

图论:点和边

最短路

多源最短路

一.定义:若干个点到其他点的最短路

disi,j<=disi,k+disk,j(三角不等式)

当且仅当k在i到j的最短路上,取等

二.算法:

Floyed(多源最短路只有这一个算法)

1.本质:dp

2.f[i][j]表示的起点是 i ,终点是 j ,转折点是 k(当然这里没有被表示出来,只不过是在for循环中有所体现)

3.初始化:若i==j 那就是0,否则就是INF ,然后后面输入每条边的价值

	for(int k=1;k<=n,k++) // 注意k要放在最外层的循环
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				if(r[i][j]>r[i][k]+r[j][k])
				r[i][j]=r[j][i]=r[i][k]+r[j][k];

单源最短路

一.定义:一个点到其它点的最短路

二.算法

Dijkstra:边权必须为正

贪心求最短点,改用松弛求其他点,如此反复

朴素时间复杂度:O(nm),找点n次,松弛边m

堆优化O((n+m)log(n+m)),找点用堆实现

// Dijkstra
void dijkstra(int n,int s){
    for(int i=1;i<=n;i++){
        int x;//x标记当前最短w的点
        int min_dis=INF;//记录当前最小距离
 
        for(int y=1;y<=n;y++){
            if(!vis[y] && min_dis>=dis[y]){
                x=y;
                min_dis=dis[x];
            }
        }

        vis[x]=true;
 
        for(int y=1;y<=n;y++) 
            dis[y]=min(dis[y],dis[x]+G[x][y]);
    }
}

SPFA 是把可能改变其他店最短路的点放进队列中,取出更新

// SPFA
int dis[N];
bool vis[N];
void SPFA(int S) {
    memset(vis, false, sizeof(vis));
    memset(dis, INF, sizeof(dis));
    dis[S] = 0;

    queue<int> Q;
    Q.push(S);

    while (!Q.empty()) {
        int x = Q.front();
        Q.pop();
        vis[x] = false;
        for (int i = head[x]; i != -1; i = edge[i].next) {
            int to = edge[i].to;
            if (dis[to] > dis[x] + edge[i].dis) {
                dis[to] = dis[x] + edge[i].dis;
                if (!vis[to]) {
                    vis[to] = true;
                    Q.push(to);
                }
            }
        }
    }
}

总结

1.判断多源还是单源最短路

2.如果是单源最短路,看看边权是不是为负,非负可以用Dijkatra或者SPFA,有负边权只能SPFA

Dijkstra(不能处理负边权,具体见link)

#include<bits/stdc++.h>
#define int long long 
const int N = 2e6 + 5;
const int INF = 0x3f3f3f3f;
using namespace std;

inline int read()
{
	int s = 0 ;
	char ch = getchar();
	bool f = true;
	while(ch < '0' || ch > '9')
	{
		if(ch == '-') f = false;
		ch = getchar();
	}
	while(ch >='0' && ch<='9')
	{
		s = s * 10 + ch - '0';
		ch = getchar(); 
	}
	return f ? s : ~s + 1;
} 

int n,m,s,f[N],vis[N];

struct nod{
	int no,w;
	bool operator < (const nod &x) const {
		return x.w < w;
	}	
};

priority_queue<nod>q;

struct node{
	int v,w,next;
}edge[N];int cnt,head[N];

inline void add(int u,int v,int w)
{
	cnt++;
	edge[cnt].v = v;
	edge[cnt].w = w;
	edge[cnt].next = head[u];
	head[u] = cnt;
}

inline void Dijkstra() 
{
	for(int i=1;i<=n;i++) f[i] = INF;f[s] = 0;
	q.push(nod{s,0});
	while(!q.empty())
	{
		int now = q.top().no;q.pop();
		if(vis[now]) continue;vis[now] = 1;
		for(int i=head[now];i;i=edge[i].next)
		{
			int v = edge[i].v , w = edge[i].w;
			if(f[v] > f[now] + w)
			{
				f[v] = f[now] + w;
				if(!vis[v])	q.push(nod{v,f[v]});
			}
		}
	}
}

signed main()	
{
	n = read();m = read();s = read(); 
	for(int i=1;i<=m;i++)
	{
		int u = read() , v = read() , w = read();
		add(u,v,w);
	}
//	spfa(); TLE
	Dijkstra();
	for(int i=1;i<=n;i++) cout << f[i] << " ";
	return 0;
}

spfa(TLE大法)

#include<bits/stdc++.h>
#define int long long 
const int N = 2e6 + 5;
const int INF = 2147483647;
using namespace std;

inline int read()
{
	int s = 0 ;
	char ch = getchar();
	bool f = true;
	while(ch < '0' || ch > '9')
	{
		if(ch == '-') f = false;
		ch = getchar();
	}
	while(ch >='0' && ch<='9')
	{
		s = s * 10 + ch - '0';
		ch = getchar(); 
	}
	return f ? s : ~s + 1;
} 

int n,m,s,f[N],vis[N];
queue<int>q;

struct node{
	int v,w,next;
}edge[N];int cnt,head[N];

inline void add(int u,int v,int w)
{
	cnt++;
	edge[cnt].v = v;
	edge[cnt].w = w;
	edge[cnt].next = head[u];
	head[u] = cnt;
}

inline void spfa()
{
	for(int i=1;i<=n;i++) f[i] = INF;f[s] = 0 ;
	q.push(s);
	while(!q.empty())
	{
		int now = q.front();q.pop();
		vis[now] = 0;
		for(int i=head[now];i;i=edge[i].next)
		{
			int v = edge[i].v , w = edge[i].w;
			if(f[v] > f[now] + w)
			{
				f[v] = f[now] + w;
				if(!vis[v]) q.push(v) , vis[v] = 1;
			}
		}
	}
}

signed main()	
{
	n = read();m = read();s = read();
	for(int i=1;i<=m;i++)
	{
		int u = read() , v = read() , w = read();
		add(u,v,w);
	}
	spfa();
	for(int i=1;i<=n;i++)  
	{
		if(s == i)
		{
			cout << 0 << " ";
			continue; 
		}
		if(f[i]) cout << f[i] << " "; 
		else cout << INF << " ";
	}
	return 0;
}

__EOF__

  • 本文作者: Low_key_smile
  • 本文链接: https://www.cnblogs.com/Low-key-smile/p/16724562.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • posted @   Low_key_smile  阅读(46)  评论(0编辑  收藏  举报
    相关博文:
    阅读排行:
    · 本地部署 DeepSeek:小白也能轻松搞定!
    · 如何给本地部署的DeepSeek投喂数据,让他更懂你
    · 从 Windows Forms 到微服务的经验教训
    · 李飞飞的50美金比肩DeepSeek把CEO忽悠瘸了,倒霉的却是程序员
    · 超详细,DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方Dee
    //music
    点击右上角即可分享
    微信分享提示