[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\n",dp[t][0], y[t]); 118 dfs(t); printf("%d\n", t); 119 } 120 RT 0; 121 }