最短路问题

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

1.Floyd
2.Dijkstra
3.SPFA

图论:点和边

最短路

多源最短路

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

\(dis_{i,j} <= dis_{i,k} + dis_{k,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;
}
posted @ 2022-09-23 22:30  Low_key_smile  阅读(34)  评论(0编辑  收藏  举报
//music