最短路计数,次短路计数

https://www.acwing.com/problem/content/385/

acwing 1134.最短路计数

①$bfs$ 每个点只出队一次,且入队一次

②$dijkstra$ 每个点第一次出队的序列一定满足拓扑序

③$bellman-ford(spfa)$ 出队的时候都不一定是满足最小,每个点可能出队多次,有可能更新前面已经出队的点,不具备拓扑序

但是要用$spfa$求最短路径数,也是可以的。比如当边权有负数时,就只能用$spfa$,先用$spfa$跑一遍,将每个点的最短路径跑出,然后建立最短路径树,在树上进行$dp$(拓扑排序)。

当$dis[j] > dis[t] + 1$时,转移,并将$cnt[t]$的值赋给$cnt[j]$, 当$dis[j] = dis[t] + 1$时,累加,将$cnt[j] = (cnt[j] + cnt[t])$。

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstring>
 4 #include <queue>
 5 
 6 using namespace std;
 7 
 8 const int mod = 100003;
 9 
10 const int N = 1e5 + 10, M = 4e5 + 10;
11 int e[M], ne[M], h[N], idx;
12 int dis[N];
13 bool st[N];
14 int cnt[N];
15 int n, m;
16 
17 void add(int a, int b)
18 {
19     e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
20 }
21 
22 void bfs()
23 {
24     memset(dis, 0x3f, sizeof dis);
25     dis[1] = 0;
26     cnt[1] = 1;
27     queue<int> q;
28     q.push(1);
29     
30     while(q.size())
31     {
32         int t = q.front();
33         q.pop();
34         
35         for(int i = h[t] ; ~ i ; i = ne[i])
36         {
37             int j = e[i];
38             if(dis[j] > dis[t] + 1)
39             {
40                 dis[j] = dis[t] + 1;
41                 cnt[j] = cnt[t];
42                 q.push(j);
43             }
44             else if(dis[j] == dis[t] + 1)
45             {
46                 cnt[j] = (cnt[j] + cnt[t]) % mod;
47             }
48         }
49     }
50 }
51 
52 int main(){
53     cin >> n >> m;
54     
55     memset(h, -1, sizeof h);
56     while(m --)
57     {
58         int a, b;
59         cin >> a >> b;
60         add(a, b), add(b, a);
61     }
62     
63     bfs();
64     
65     for(int i = 1 ; i <= n ; i ++)cout << cnt[i] << endl;
66     return 0;
67 }

 

 

https://www.acwing.com/activity/content/problem/content/1506/1/

acwing 383.观光

 

在求最短路数的基础上进行求次短路数。和在树中求最大直径和次大直径的方法一样。在最短路数的基础上:

如果当前小于最短路,先更新次短路数,加入堆,再更新最短路数,加入堆;

再如果当前等于最短路,累加最短路数;

再如果当前小于次短路,更新次短路数,加入堆;

最后如果当前等于次短路数,累加次短路数。

次短路数和最短路数一样,都是满足拓扑序的,所以使用$dijkstra$算法求解。

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <queue>
 4 #include <cstring>
 5 #include <vector>
 6 
 7 using namespace std;
 8 
 9 const int N = 1010, M = 20010;
10 
11 struct Node{
12     int ver, type, dis;
13     bool operator > (const Node &W)const{
14         return dis > W.dis;
15     }
16 };
17 
18 int e[M], ne[M], w[M], h[N], idx;
19 int dis[N][2], cnt[N][2];
20 bool st[N][2];
21 int n, m;
22 int S, E;
23 
24 void add(int a, int b, int c)
25 {
26     e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
27 }
28 
29 int dijkstra()
30 {
31     memset(st, 0, sizeof st);
32     memset(dis, 0x3f, sizeof dis);
33     memset(cnt, 0, sizeof cnt);//多组测试数据必须全部初始化
34     priority_queue<Node, vector<Node>, greater<Node>> heap;
35     dis[S][0] = 0;
36     cnt[S][0] = 1;//最开始没有次短路
37     heap.push({S, 0, 0});
38     
39     while(heap.size())
40     {
41         Node t = heap.top();
42         heap.pop();
43         
44         int ver = t.ver, type = t.type, distance = t.dis, count = cnt[ver][type];
45         if(st[ver][type])continue;
46         st[ver][type] = true;
47         
48         for(int i = h[ver] ; ~ i ; i = ne[i])
49         {
50             int j = e[i];
51             if(dis[j][0] > distance + w[i])//分别对应一二三四种情况。
52             {
53                 dis[j][1] = dis[j][0], cnt[j][1] = cnt[j][0];
54                 heap.push({j, 1, dis[j][1]});
55                 dis[j][0] = distance + w[i], cnt[j][0] = count;
56                 heap.push({j, 0, dis[j][0]});
57             }
58             else if(dis[j][0] == distance + w[i])cnt[j][0] += count;
59             else if(dis[j][1] > distance + w[i])
60             {
61                 dis[j][1] = distance + w[i], cnt[j][1] = count;
62                 heap.push({j, 1, dis[j][1]});
63             }
64             else if(dis[j][1] == distance + w[i])cnt[j][1] += count;
65         }
66     }
67     int res = cnt[E][0];
68     if(dis[E][0] + 1 == dis[E][1])res += cnt[E][1];
69     return res;
70 }
71 
72 int main(){
73     int T;
74     cin >> T;
75     while(T --)
76     {
77         cin >> n >> m;
78         memset(h, -1, sizeof h);
79         idx = 0;//注意多组数据,idx和表头都要初始化
80         while(m --)
81         {
82             int a, b, c;
83             cin >> a >> b >> c;
84             add(a, b, c);
85         }
86         
87         cin >> S >> E;
88         
89         cout << dijkstra() << endl;
90     }
91     return 0;
92 }

 

posted @ 2020-03-21 17:44  dzcixy  阅读(207)  评论(0)    收藏  举报