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 }
View Code

 

posted @ 2019-06-01 22:47  缘未到  阅读(159)  评论(0编辑  收藏  举报