HDU 1688 Sightseeing 【输出最短路+次短路条数】
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1688
题目大意:给n个点,m条有向边。再给出起点s, 终点t。求出s到t的最短路条数+次短路条数。
思路:
1.最短路和次短路是紧密相连的,在最短路松弛操作中,当我们找到一条更短的路径,也就意味着之前的路径不再是最短路,而成为了次短路,利用这个关系可以实现状态的转移。
2.好久没写优先队列了,都忘记了加个 priority_queue, 这样才能写重载,才能排序。
注释在代码里:
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #define mem(a, b) memset(a, b, sizeof(a)) 5 const int inf = 0x3f3f3f3f; 6 using namespace std; 7 8 int n, m; 9 int tot, head[1100]; 10 int dis[2][1100], cnt[2][1100];//dis数组记录最短路 0 和次短路 1 距离,cnt数组记录最短路 0 和次短路 1 条数 11 int vis[2][1100]; 12 13 struct Edge 14 { 15 int to, next; 16 int w; 17 }edge[100010]; 18 19 void add(int a, int b, int w) 20 { 21 edge[++ tot].to = b; 22 edge[tot].w = w; 23 edge[tot].next = head[a]; 24 head[a] = tot; 25 } 26 27 struct Node//优先队列优化结构体,id为点的序号, dis为源点到该点的距离 p区分属于最短路还是次短路 28 { 29 int id, dis, p; 30 bool operator < (const Node &a)const 31 { 32 return dis > a.dis; 33 } 34 }no; 35 36 void init() 37 { 38 mem(head, -1), tot = 0; 39 mem(vis, 0); //代表源点到该点的距离未被确定 40 } 41 42 void dij(int s, int t) 43 { 44 priority_queue<Node> Q; 45 while(!Q.empty()) 46 Q.pop(); 47 for(int i = 1; i <= n; i ++) //初始化 48 { 49 dis[0][i] = dis[1][i] = inf; 50 cnt[0][i] = cnt[1][i] = 0; 51 } 52 dis[0][s] = 0; 53 cnt[0][s] = 1;//源点到自己的最短路条数为1 54 no.p = 0, no.dis = 0, no.id = s; 55 Q.push(no); 56 while(!Q.empty()) 57 { 58 Node a = Q.top(); 59 Q.pop(); 60 if(vis[a.p][a.id]) 61 continue; //该p状态下已经确定过就跳过 62 vis[a.p][a.id] = 1; 63 for(int i = head[a.id]; i != -1; i = edge[i].next) 64 { 65 int to = edge[i].to; 66 if(dis[0][to] > dis[a.p][a.id] + edge[i].w) //最短路可以更新(在0或1状态下找到一条更短的路) 67 { 68 dis[1][to] = dis[0][to]; //原来的最短路成为次短路 69 dis[0][to] = dis[a.p][a.id] + edge[i].w; 70 cnt[1][to] = cnt[0][to];//次短路条数继承为原来的最短路条数 71 cnt[0][to] = cnt[a.p][a.id]; 72 no.p = 0, no.dis = dis[0][to], no.id = to; 73 Q.push(no); 74 no.p = 1, no.dis = dis[1][to], no.id = to; 75 Q.push(no); 76 } 77 else if(dis[0][to] == dis[a.p][a.id] + edge[i].w)//最短路长度一样 更新最短路条数即可 78 { 79 cnt[0][to] += cnt[a.p][a.id]; 80 } 81 else if(dis[1][to] > dis[a.p][a.id] + edge[i].w)//找到一条长度大于最短路但小于当前次短路的路径 82 {//将这条路变成次短路 83 dis[1][to] = dis[a.p][a.id] + edge[i].w; 84 cnt[1][to] = cnt[a.p][a.id]; 85 no.p = 1, no.dis = dis[1][to], no.id = to; 86 Q.push(no); 87 } 88 else if(dis[1][to] == dis[a.p][a.id] + edge[i].w) 89 { 90 cnt[1][to] += cnt[a.p][a.id]; 91 } 92 } 93 } 94 } 95 96 int main() 97 { 98 int T; 99 scanf("%d", &T); 100 while(T --) 101 { 102 init(); 103 scanf("%d%d", &n, &m); 104 for(int i = 1; i <= m; i ++) 105 { 106 int a, b, c; 107 scanf("%d%d%d", &a, &b, &c); 108 add(a, b, c); 109 } 110 int s, t; 111 scanf("%d%d", &s, &t); 112 dij(s, t); 113 int ans = cnt[0][t]; //ans代表最短路的条数 114 if(dis[0][t] + 1 == dis[1][t]) 115 ans += cnt[1][t]; 116 printf("%d\n", ans); 117 } 118 return 0; 119 }