dijkstra是一種單元最短路徑算法,其能在較好時間復雜度內處理這一問題。但其對負權圈的處理讓人不太滿意——會陷入死循環
其思想和Prim算法差不多,都是貪心。
把圖中的所有點划分為兩個集合:包含遠點S和不包含原點S的
每次從不包含原點S的集合中找出一個離原點S最近的點(這樣就沒有點能夠比這個點更加接近原點,這也是其不能處理負權邊的原因)
我們先考慮簡單一點的情況:沒有負權邊
設u是不包含s中dist最小的那個點,另外v是不包含S中的任意點
如果v能更新u點<==>dist[v]+map[v][u]<dist[u];因為map[v][u]>0所以有dist[v]<dist[u]假設不成立
所以我們就有一個算法啦
1.每次找出不包含S中最近點,加入包含s的集合
2.維護所有和這個店相連的不在包含s的集合里的點到原點的距離(Prim維護的是到包含S的集合的距離)
時間復雜度Θ(n^2)比較優,適合稠密圖。
但我們發現每次找一個最近點有點耗時,因為要支持減值和求最小的操作,就用優先隊列啦
(優先隊列在小根堆情況下支持降值,大根堆下支持升值)但優先隊列里的元素有O(E)個開空間時需注意~~
上代碼~
轉自HK大神的blog,對於重載()不是很懂
#include<iostream> #include<cstdio> #include<queue> using namespace std; int n,m,S,tot,Next[500010],head[20000],tree[500010],val[500010]; bool visit[20000]; long long dis[20000]; struct cmp { bool operator()(int a,int b) { return dis[a]>dis[b]; } }; priority_queue<int,vector<int>,cmp> Q; void add(int x,int y,int z) { tot++; Next[tot]=head[x]; head[x]=tot; tree[tot]=y; val[tot]=z; } int main() { scanf("%d%d%d",&n,&m,&S); tot=0; for (int i=1;i<=m;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); if (x==y) continue; add(x,y,z); } for (int i=1;i<=n;i++) { visit[i]=false; dis[i]=2147483647; } Q.push(S); dis[S]=0; while (!Q.empty()) { int u=Q.top(); Q.pop(); if (visit[u]) continue; visit[u]=true; for (int i=head[u];i;i=Next[i]) { int v=tree[i]; if (!visit[v]&&dis[v]>dis[u]+(long long)val[i]) { dis[v]=dis[u]+val[i]; Q.push(v); } } } for (int i=1;i<=n-1;i++) printf("%lld ",dis[i]); printf("%lld\n",dis[n]); return 0; }
下面自己寫的,渣~(我會告訴你我懶)
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #define N 2000005 using namespace std; int n,m,s,next[N],to[N],head[N],vis[N],cos[N],dis[N],num=0,u,v,c; struct note{ int to,cos; }; struct cmp { bool operator()(int a,int b) { return dis[a]>dis[b]; } }; priority_queue<int,vector<int>,cmp> Q; void push_way(int u,int v,int c) { to[++num]=v; cos[num]=c; next[num]=head[u]; head[u]=num; } void dijkstra(int s) { Q.push(s); //vis[s]=1; dis[s]=0; while(!Q.empty()) { int u=Q.top(); Q.pop(); if(vis[u]) continue; cout<<u<<endl; vis[u]=1; for(int i=head[u];i;i=next[i]) { int v=to[i]; if(!vis[v]&&dis[v]>dis[u]+cos[i]) { dis[v]=dis[u]+cos[i]; Q.push(v); } } } for(int i=1;i<=n;i++) { cout<<dis[i]<<' '; } cout<<endl; } int main() { scanf("%d %d %d",&n,&m,&s); for(int i=1;i<=n;i++) dis[i]=10000; for(int i=1;i<=m;i++) { scanf("%d %d %d",&u,&v,&c); push_way(u,v,c); } dijkstra(s); }