poj3255:Roadblocks
求次短路径长度
这道题的做法和最短路径基本一致,唯一的不同点在于,在求出最短路径的情况下必须要保留下次短路径。对于Dijkstra判断中取出的每一个点,如果到它的最短距离大于当前该点的次短距离,则当前该点已经取到最短距离和次短距离,不进行操作,否则进行两次判断:如果小于最短边,则赋给最短变,并将原最短边成为次短边;或者如果大于最短边且小于次短边,则赋给次短边。两次完成之后均要加入队列。参考:
#include
#include
#include
#include
#include
using namespace std;
const int MAXV = 5000 + 10;
const int INF = INT_MAX;
//邻接表存储图
struct Edge{
int to, cost;
Edge(int t, int c): to(t), cost(c) {}
};
vector G[MAXV];
//优先级队列中存储的邻接点结构
struct Point{
int distance, vertex;
Point(int d, int v): distance(d), vertex(v) {}
/*此处重载<,目的是实现在优先级队列(默认是大根堆)中distance较小的在堆顶
* distance大的优先级小*/
bool operator < (const Point& p) const {
return distance > p.distance;
}
};
int dist[MAXV]; //最短距离
int dist2[MAXV]; //次短距离
void Dijkstra(int start, int n){
priority_queue que;
//注意此处初始化时dist和dist2均向后偏移,因为顶点编号为1~n,若为0~n-1则不需要偏移
fill(dist + 1, dist + 1 + n, INF);
fill(dist2 + 1, dist2 + 1 + n, INF);
dist[start] = 0;
que.push(Point(0, start));
while(!que.empty()){
Point p = que.top();
que.pop();
int v = p.vertex;
int d = p.distance;
/*若从优先级队列中取出的点的距离大于次短距离
* 则最短距离和次短距离都已经更新过了,直接跳过这个点即可*/
if (dist2[v] < d){
continue;
}
for (int i = 0; i < G[v].size(); ++i) {
Edge e = G[v][i];
int d2 = d + e.cost;
if(dist[e.to] > d2){ //需要更新最短距离
swap(dist[e.to], d2); //原来的dist变为次短距离,存于d2中
que.push(Point(dist[e.to], e.to));
}
if(dist2[e.to] > d2 && dist[e.to] < d2){ //更新次短距离,且保证最短距离小于次短距离
dist2[e.to] = d2;
que.push(Point(dist2[e.to], e.to));
}
}
}
}
int main(){
int n, r;
int a, b, d;
scanf("%d%d", &n, &r);
for (int i = 0; i < r; ++i) {
scanf("%d%d%d", &a, &b, &d);
G[a].push_back(Edge(b, d));
G[b].push_back(Edge(a, d));
}
Dijkstra(1, n);
printf("%d\n", dist2[n]);
return 0;
}