[PAT L2-001] 紧急救援(spfa,最短路计数, dp)

题目链接:https://www.patest.cn/contests/gplt/L2-001

用一个数组dp(i,j)表示到i点的时候的最短路个数,dp(i,0)表示在松弛操作时已经更新了最短路的个数,dp(i,1)表示未更新。

当在松弛操作d(v) > d(u) + w的时候是一定会被更新的,并且最短路有且仅有这么一条,那么更新dp(v,1)=dp(v,0),dp(v,1)=dp(u,0)。

若d(v) = d(u) + w的时候,说明这个点可以从两条边过来,并且路径都是最短的。那么会被更新,dp(v,1)=dp(v,0),同时把之前到u点的最短路条数更新到v上,dp(v,0)+=(dp(u,0)-dp(u,1))。

关于救援队的计数,每当走到一个点若进行了松弛操作,就更新一下最大值就行了。假如d[v] == d[u] + w还要考虑这两条最短路上哪个点的救援队多,再更新。

关于路径,在更新救援队数量的时候记住上一个点,最后输出时递归即可。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 #define fr first
  4 #define sc second
  5 #define cl clear
  6 #define BUG puts("here!!!")
  7 #define W(a) while(a--)
  8 #define pb(a) push_back(a)
  9 #define Rint(a) scanf("%d", &a)
 10 #define Rll(a) scanf("%lld", &a)
 11 #define Rs(a) scanf("%s", a)
 12 #define Cin(a) cin >> a
 13 #define FRead() freopen("in", "r", stdin)
 14 #define FWrite() freopen("out", "w", stdout)
 15 #define Rep(i, len) for(int i = 0; i < (len); i++)
 16 #define For(i, a, len) for(int i = (a); i < (len); i++)
 17 #define Cls(a) memset((a), 0, sizeof(a))
 18 #define Clr(a, x) memset((a), (x), sizeof(a))
 19 #define Full(a) memset((a), 0x7f7f7f, sizeof(a))
 20 #define lrt rt << 1
 21 #define rrt rt << 1 | 1
 22 #define pi 3.14159265359
 23 #define RT return
 24 #define lowbit(x) x & (-x)
 25 #define onenum(x) __builtin_popcount(x)
 26 typedef long long LL;
 27 typedef long double LD;
 28 typedef unsigned long long ULL;
 29 typedef pair<int, int> pii;
 30 typedef pair<string, int> psi;
 31 typedef pair<LL, LL> pll;
 32 typedef map<string, int> msi;
 33 typedef vector<int> vi;
 34 typedef vector<LL> vl;
 35 typedef vector<vl> vvl;
 36 typedef vector<bool> vb;
 37 
 38 const int maxn = 600;
 39 const int maxm = maxn * maxn;
 40 const int inf = 0x7f7f7f7f;
 41 typedef struct Edge {
 42   int v, w;
 43   int next;
 44   Edge() { next = -1; }
 45 }Edge;
 46 
 47 int n, m, s, t;
 48 Edge edge[maxm];
 49 int head[maxm], ecnt;
 50 int pre[maxm], dp[maxm][2];
 51 int d[maxm], x[maxm], y[maxm];
 52 queue<int> q;
 53 bool vis[maxn];
 54 int u, v, w;
 55 
 56 void adde(int u, int v, int w) {
 57   edge[ecnt].v = v; edge[ecnt].w = w;
 58   edge[ecnt].next = head[u]; head[u] = ecnt++;
 59 }
 60 
 61 void init() {
 62   Clr(head, -1); ecnt = 0; Cls(vis);
 63   Cls(edge); Cls(dp); Clr(pre, -1);
 64   Rep(i, n) {
 65     Rint(x[i]);
 66     y[i] = x[i];
 67   }
 68   Rep(i, m) {
 69     Rint(u); Rint(v); Rint(w);
 70     adde(u,v,w); adde(v,u,w);
 71   }
 72 }
 73 
 74 void spfa(int s) {
 75   while(!q.empty()) q.pop();
 76   Rep(i, n+1) d[i] = inf;
 77   d[s] = 0; q.push(s); dp[s][0] = 1;
 78   vis[s] = 1;
 79   while(!q.empty()) {
 80     int u = q.front(); q.pop(); vis[u] = 0;
 81     for(int i = head[u]; ~i; i=edge[i].next) {
 82       int v = edge[i].v;
 83       int w = edge[i].w;
 84       if(v == u) continue;
 85       if(d[v] > d[u] + w) {
 86         d[v] = d[u] + w;
 87         if(!vis[v]) vis[v] = 1, q.push(v);
 88         pre[v] = u;
 89         y[v] = y[u] + x[v];
 90         dp[v][1] = dp[v][0];
 91         dp[v][0] = dp[u][0];
 92       }
 93       else if(d[v] == d[u] + w) {
 94         if(!vis[v]) vis[v] = 1, q.push(v);
 95         if(y[v] < y[u] + x[v]) {
 96           y[v] = y[u] + x[v];
 97           pre[v] = u;
 98         }
 99         dp[v][1] = dp[v][0];
100         dp[v][0] += (dp[u][0] - dp[u][1]);
101       }
102     }
103   }
104 }
105 
106 void dfs(int u) {
107   if(pre[u] == -1) return;
108   dfs(pre[u]);
109   printf("%d ", pre[u]);
110 }
111 
112 signed main(){
113   //FRead();
114   while(~scanf("%d%d%d%d",&n,&m,&s,&t)) {
115     init();
116     spfa(s);
117     printf("%d %d
",dp[t][0], y[t]);
118     dfs(t); printf("%d
", t);
119   }
120   RT 0;
121 }
原文地址:https://www.cnblogs.com/kirai/p/5885197.html