1. 程式人生 > >最短路中的路徑還原問題

最短路中的路徑還原問題

問題描述:
求出源點1到頂點3的最短路長度並依次輸出該路徑上的頂點
程式碼:

struct edge
{
    int to;
    int next;
    int w;
};
edge e[500010];
int head[10010];
int cnt = 1;

int n,m;
bool book[10010];
int dis[10010],prev[10010];//prev記錄前驅
void add_edge(int u,int v,int w)
{
    e[cnt].to = v;
    e[cnt].next = head[u];
    e[cnt].w = w;
    head[u] = cnt;
    cnt++;
}
void
dijkstra(int s) { memset(dis,0x3F,sizeof(dis));//初始化 memset(prev,-1,sizeof(prev));//初始化 dis[s] = 0; // for(int i = head[s]; i != -1; i = e[i].next) // { // int to = e[i].to; // int w = e[i].w; // dis[to] = min(dis[to],w);//在此處進行判斷 // } // book[s] = true; int p; for(int
i = 1; i <= n - 1; ++i) { int min_w = inf; // s可以到達p不等於s與p之間有邊相連 // for(int j = head[s]; j != -1; j = e[j].next) // { // int to = e[j].to; // int w = e[j].w; // if(book[to] == false && dis[to] < min_w) // { // min_w = dis[to];
// p = to; // } // } for(int j = 1; j <= n; ++j) { if(book[j] == false && dis[j] < min_w) { min_w = dis[j]; p = j; } } book[p] = true; for(int j = head[p]; j != -1; j = e[j].next) { int to = e[j].to; int w = e[j].w; if(dis[to] > dis[p] + w && book[to] == false) { dis[to] = dis[p] + w; prev[to] = p;//中轉點p成為了頂點to的前驅頂點 } } } return; } vector<int> get_path(int n) { vector<int> v; for(int i = n; i != -1; i = prev[i])//從頂點n開始,向前回溯,直到到達源點 v.push_back(i); reverse(v.begin(),v.end());//翻轉 return v; } int main() { cin >> n >> m; memset(head,-1,sizeof(head));//初始化 for(int i = 1; i <= m; ++i) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add_edge(u,v,w); } dijkstra(1); for(int i = 1; i <= n; i++)//輸出 { if(dis[i] == inf) printf("2147483647 "); else printf("%d ",dis[i]); } cout << endl; vector<int> path = get_path(3);//還原1->3的路徑 for(int i = 0; i <= path.size() - 1; ++i)//輸出路徑 printf("%d ",path[i]); cout << endl; return 0; }

解決方法:
程式碼部分有兩處被註釋,第一處是對dis陣列的初始化,這完全是多此一舉,而且由於重邊的存在,不寫取min會WA,還增長了程式碼長度。直接將源點進行標記,用源點去鬆弛源點到其餘各點的距離就行,不會產生什麼負面影響。如果要寫這部分的話,還應在程式碼中加入求prev的語句。
第二處是在求到源點的最短距離的頂點時,錯誤地僅在與源點直接有邊的頂點中去找,對程式碼思想不夠掌握,造成了錯誤。
當更新prev[to] = p;時,prev[p]已被求出。