这道题我采用了spfa+dfs的思路。最近在备考PAT,打算把这道题当作模版题之一,以后随时拿来复习。
这道题注意的要点如下:
-
这道题中不仅要输出救生队最大数目,还要输出最短路径数目,其中救生队最大数目可以直接在spfa中得到,最短路径数目则不可以,因为有可能重复统计,所以需要在dfs中得到。
-
dfs需要从后往前遍历,因此需要记录每个点的前驱。如果采用vector数组实现图的存储,要注意记录前驱和记录后继要采用两个数组a和b,不可以用记录后继的数组遍历前驱。
#include <iostream> #include<vector> #include<cstdio> #include<algorithm> #include<cmath> #include<map> #include<cstdlib> #include<queue> #include<cstring> #include<set> using namespace std; int n,m,s,t; int ww[520]; int in[520]={0};//节点是否在队列中 int dis[520]; int maxw[520]={0};//最大的点权 int num[520]={0}; queue<int>q; struct Node { int v; int w; int u; Node(int _u,int _v,int _w):u(_u),v(_v),w(_w){ } }; vector<Node>a[520]; vector<Node>b[520]; int ans=0; int level=0; void dfs(int head) { if(head==s) { ans++; return; } for(int i=0;i<b[head].size();i++) { int u=b[head][i].u; int w=b[head][i].w; if(dis[u]+w==dis[head]) { dfs(u); } } } int main() { scanf("%d%d%d%d",&n,&m,&s,&t); for(int i=0;i<n;i++) scanf("%d",&ww[i]); for(int i=1;i<=m;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); a[x].push_back(Node(x,y,z)); a[y].push_back(Node(y,x,z)); b[y].push_back(Node(x,y,z)); b[x].push_back(Node(y,x,z)); } in[s]=1; fill(dis+0,dis+n,0x3f3f3f3f); dis[s]=0; q.push(s); maxw[s]=ww[s]; while(!q.empty()) { int head = q.front(); q.pop(); in[head] = 0; for (int i = 0; i < a[head].size(); i++) { int v = a[head][i].v; int w = a[head][i].w; if (dis[head] + w < dis[v]) { dis[v] = dis[head] + w; maxw[v] = maxw[head] + ww[v]; if (!in[v]) { q.push(v); in[v] = 1; } } else if (dis[head] + w == dis[v]) { if (maxw[v] < maxw[head] + ww[v]) { maxw[v] = maxw[head] + ww[v]; if (!in[v]) { q.push(v); in[v] = 1; } } } } } dfs(t); cout<<ans<<" "<<maxw[t]; }