最短路模板合集

本文整理了最短路算法模板,包括线段树优化的Dijkstra、处理负权值的SPFA及其优化,以及Floyd算法等。同时,探讨了最长路问题,指出不能使用Dijkstra,推荐使用Bellman-Ford、SPFA或Floyd-Warshall算法。
摘要由CSDN通过智能技术生成

整理的算法模板合集: ACM模板


∮ 1. 最短路

优先队列最短路

struct Edge
{
   
    ll v,w,next;//v:目的地,w:距离,next:下一个节点
}G[N];
ll head[N],cnt,n,m,s;
ll dis[N];//存距离
inline void addedge(ll u,ll v,ll w)//链式前向星存图
{
   
    cnt++;
    G[cnt].w=w;
    G[cnt].v=v;
    G[cnt].next=head[u];
    head[u]=cnt;
}
struct node
{
   
    ll d,u;//d是距离u是起点
    bool operator<(const node& t)const//重载运算符
    {
   
        return d>t.d;
    }
};
inline void Dijkstra()
{
   
    for(register int i=1;i<=n;++i)dis[i]=mod;//初始化
    dis[s]=0;
    priority_queue<node>q;//堆优化
    q.push((node){
   0,s});//起点push进去
    while(!q.empty())
    {
   
        node tmp=q.top();q.pop();
        ll u=tmp.u,d=tmp.d;
        if(d!=dis[u])continue;//松弛操作剪枝
        for(register int i=head[u];i;i=G[i].next)//链式前向星
        {
   
            ll v=G[i].v,w=G[i].w;
            if(dis[u]+w<dis[v])//符合条件就更新
            {
   
                dis[v]=dis[u]+w;
                q.push((node){
   dis[v],v});//沿着边往下走
            }
        }
    }
}
int main()
{
   
    scanf("%lld %lld %lld",&n,&m,&s);
    for(register int i=1;i<=m;++i)
    {
   
        ll x,y,z;
        scanf("%lld %lld %lld",&x,&y,&z);
        addedge(x,y,z);//建图
    }
    Dijkstra();
    for(register int i=1;i<=n;++i)
        printf("%lld ",dis[i]);
    printf("\n");
    return 0;
}

1.1 线段树优化的 D i j k s t r a Dijkstra Dijkstra

时间和内存均是优先队列优化版本的 1 2 \frac{1}{2} 21

int n, m;
struct edge {
   
	int to, w, nxt;
	edge() {
   }
	edge(int t, int ww, int nn) {
   to = t, w = ww, nxt = nn;}
}e[maxn << 1];
 
int head[maxn], k = 0;
void add(int u, int v, int w) {
   e[k] = edge(v, w, head[u]); head[u] = k++;}
 
ll ans[maxn];
struct node {
   
	ll dis; int x;
	node() {
   }
	node(ll d, int xx) {
   dis = d, x = xx;}
}dis[maxn << 2];
 
//建树初始化,主要是编号也要返回所以要先预处理一下 
void build(int p, int l, int r) {
   
	if(l == r) {
   dis[p].x = l; return;}
	int mid = l + r >> 1;
	build(p << 1, l, mid); build(p << 1 | 1, mid + 1, r);
	dis[p].x = dis[p << 1].x;
}
 
void change(int p, int l, int r, int x, int y) {
   
	if(l == r) {
   dis[p].dis = y; return;}
	int mid = l + r >> 1;
	if(x <= mid) change(p << 1, l, mid, x, y);
	else change(p << 1 | 1, mid + 1, r, x, y);//单点修改的板子操作 
	if(dis[p << 1].dis < dis[p << 1 | 1].dis) dis[p] = dis[p << 1];
	else dis[p] = dis[p << 1 | 1];
}
 
//因为用距离得到最小,但是需要的是编号,所以返回node 
node ask(int p, int l, int r, int ls, int rs) {
   
	if(ls <= l && r <= rs) {
   return dis[p];}
	int mid = l + r >> 1; node ans = node(inf, 0), tmp;
	if(ls <= mid) ans = ask(p << 1, l, mid, ls, rs);
	if(rs > mid) {
   
		node tmp = ask(p << 1 | 1, mid + 1, r, ls, rs);
		if(ans.dis > tmp.dis) ans = tmp;
	}
	return ans;
}
 
int S;
void dij() {
   
	for(int k = 1; k < n; k++) {
   //n-1次够用的。虽然我也不知道为什么最后n次跑的比n-1次还要快…… 
		register int u = ask(1, 1, n, 1, n).x;
		for(int i = head[u]; ~i; i = e[i].nxt) {
   
			register int v = e[i].to;
			if(ans[u] + e[i].w < ans[v]) {
   //最短路更新 
				ans[v] = ans[u] + e[i].w, change(1, 1, n, v, ans[v]);//单点修改 
			}
		}
		change(1, 1, n, u, inf);//取出来过后要赋值INF,以免再次取用 
	}
}
 
int main() {
   
	memset(head, -1, sizeof head);
	n = read(), m = read(), S = read();
	for(int u, v, w, i = 1; i <= m; i++) u = read(), v = read(), w = read(), add(u, v, w);
	
	//初始化 
	for(int i = 1; i <= (n << 2); i++) dis[i].dis = inf;
	for(int i = 1; i <= n; i++) ans[i] = inf;
	
	//线段树初始化,dis是线段树,ans是答案 
	build
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁凡さん

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值