1. 程式人生 > >(dijkstra演算法+多權值)最短路徑問題

(dijkstra演算法+多權值)最短路徑問題

給你n個點,m條無向邊,每條邊都有長度d和花費p,給你起點s終點t,要求輸出起點到終點的最短距離及其花費,如果最短距離有多條路線,則輸出花費最少的。
Input
輸入n,m,點的編號是1~n,然後是m行,每行4個數 a,b,d,p,表示a和b之間有一條邊,且其長度為d,花費為p。最後一行是兩個數 s,t;起點s,終點。n和m為0時輸入結束。
(1< n< =1000, 0< m< 100000, s != t)
Output
輸出 一行有兩個數, 最短距離及其花費。
Sample Input
3 2
1 2 5 6
2 3 4 5
1 3
0 0
Sample Output
9 11

分析與解答

這題我除錯了八個小時
我總結一下我對dijkstra的認識

1.dijkstra演算法可以求從單個源點出發到所有結點的最短路,這個題就是坑到這了,我寫兩個引數就wrong answer了,就是說,你呼叫這個函式只需要一個引數,就是起點。終點是n已經固定了,現在你說終點是t,哪怕走到終點n的路不經過t,你輸出dis[t],也是從起點到t的最短路。

這裡寫圖片描述

每標記一次就說明被標記的這個數的dis已經確定了。我們迴圈n次目的就是為了標記n次確定n個數的dis。我們初始化起點的dis是0其他的是inf,我們迴圈n次,第一個確定下來的就是起點。然後標記,注意這個標記是在那n次迴圈裡的。
2.這個題第二個坑就是,兩個點之間的路有多條,如果路的距離相同時,還要找花費最小的

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define INF 100100
using namespace std;

int vis[1100];int dis[1100];
int map[1100][1100];
int value[1100][1100];
int v[1100];
int n;
void dijkstra(int s){
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;++i){
        dis[i]=INF;
        v[i]=INF;
    }
    dis[s]=v[s]=0
; for(int i=1;i<=n;++i){//迴圈n次,每一次都選一個點標記上 int x,m=INF; for(int y=1;y<=n;++y){//所有未標號節點中選dis最小的結點 if(!vis[y]&&dis[y]<=m) m=dis[x=y]; } vis[x]=1; for(int y=1;y<=n;++y)//從x出發的所有邊(x,y),更新dis[y] { if (dis[y] > dis[x] + map[x][y]){ dis[y]= dis[x]+map[x][y]; v[y] = v[x] + value[x][y]; } else if (dis[y] == dis[x] + map[x][y] && v[y] > v[x] + value[x][y]){ v[y] = v[x] + value[x][y]; } } } } int main() { int m; int a,b,c,p; int s,t; while(cin>>n>>m){ if(m==0&&n==0) return 0; // // memset(v,INF,sizeof(v)); memset(map,INF,sizeof(map)); memset(value,INF,sizeof(value)); for(int i=0;i<m;++i){ scanf("%d%d%d%d",&a,&b,&c,&p); if(c<map[a][b]){ map[a][b]=map[b][a]=c; value[a][b]=value[b][a]=p; } if(c==map[a][b]&&value[a][b]>p){ value[b][a]=value[a][b]=p; } } scanf("%d%d",&s,&t); dijkstra(s); printf("%d %d\n",dis[t],v[t]); } }