關於SPFA——他復活了? || 最短路算法 SPFA + 堆 = Dijkstra?

網上講解又多又好 模板的話也不錯(雖然沒我的好但我現在SPFA都不打裸的了)

這裏就提供一種思路 SPFA + 堆優化 跑的快快噠

不過感覺全世界的毒瘤出題人都還會想方設法地卡SPFA 具體原因 百度 "卡SPFA" 然後隨便進去就行了

的確嘛 這算法都不正經= =

然後dalao們都是改用優先隊列存點的 但是死不用 STL 的 Frocean......

於是這裏採用堆存儲(堆和優先隊列不是同一個東西嗎) 關於距離數組 dis 用小根堆維護 每次取dis最小的點更新 等根裏沒數了就跑完了

然後據一些人所說我這個不是SPFA了??但我只是加了個堆啊QvQ 當然我去翻了下迪傑斯特拉的板子 貌似也是這樣拓展的 如果真的是的話那就......自然是更好的了 然而我真沒學過迪傑斯特拉啊QAQ 我只是把我的SPFA隊列換成堆了啊....

一般圖優化效果也比較明顯 普通模板快了 50ms 然後稠密圖優化效果極其顯著 但是如果卡這種做法的圖那就完了 雖然我沒見過

我還是覺得就是 SPFA 就不批註了 存個代碼警示一下 卡SPFA的題戳這裏

#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXN = 100010;
const int MAXM = 400010;
struct Edge {
	int next,to,v;
} e[MAXM];
int first[MAXN],dis[MAXN],heap[MAXN],tot;
short o[MAXN];
void add(int x,int y,int z)
{
	e[++tot].next = first[x];
	e[tot].to = y;
	e[tot].v = z;
	first[x] = tot;
}
void push(int p)
{
	heap[++tot] = p;
	o[p] = 1;
	int now = tot;
	while (now > 1 && dis[heap[now]] < dis[heap[now / 2]])
	swap(heap[now],heap[now / 2]),now = now / 2;
}
int pop(int p)
{
	o[heap[1]] = 0;
	int po = heap[1];
	heap[1] = heap[tot--];
	while (p * 2 <= tot && dis[heap[p]] > dis[heap[p * 2]] ||
	  (p * 2 + 1 <= tot && dis[heap[p]] > dis[heap[p * 2 + 1]]))
	{
		int nxt = p * 2;
		if (nxt + 1 <= tot && dis[heap[nxt]] > dis[heap[nxt + 1]]) ++nxt;
		swap(heap[p],heap[nxt]);
		p = nxt;
	}
	return po;
}
int main()
{
	memset(dis,0x7f,sizeof(dis));
	int n,m,s,x,y,z;
	scanf("%d%d%d",&n,&m,&s); while (m--)
	scanf("%d%d%d",&x,&y,&z),add(x,y,z);
	tot = 0;
	push(s);
	dis[s] = 0;
	while (tot)
	{
		int p = pop(1);
		for (int a = first[p],b = e[a].to ; a ; a = e[a].next,b = e[a].to)
			if (dis[p] + e[a].v < dis[b])
			{
				dis[b] = dis[p] + e[a].v;
				if (!o[b]) push(b);
			}
	}
	for (int a = 1 ; a < n ; ++ a)
	printf("%d ",dis[a]);
	printf("%d\n",dis[n]);
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章