最短路中的路徑還原問題
阿新 • • 發佈:2018-11-26
問題描述:
求出源點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]
已被求出。