L2-001 緊急救援
阿新 • • 發佈:2019-03-09
clas eve math max show ret 一道 開始 urn
這題是一道給我這個菜雞復習Dijkstra的好題。
因為要求比較多,先把大致需要的數組羅列一下。
dis[]記錄最短路
path[]記錄路徑
pnum[]記錄最短路數目
cnt[]記錄最多人數
vis[]記錄是否走過這個點
首先需要將vis和cnt置零,dis置∞(用鄰接矩記錄邊也要記得置∞)
接著對起始點初始化,dis[s]=0;path[s]=-1;pnum[s]=1;cnt[s]=s點人數;
從每個點開始,先遍歷所有點,如果找到一個沒有被訪問過的並且距離更近的點,將這點作為起點,進行松弛操作
松弛操作有兩種情況,一種是距離較大的情況,更新各個數組即可。如果距離相等,要將兩者的pnum[]和cnt[]相加。
因為用了數組記錄最短路的每個點前一個節點,所以打印路徑遞歸即可,詳見代碼
#include <iostream> #include <string.h> #include <cstdio> #include <algorithm> #include <cstdlib> #include <math.h> #include <queue> #include <vector> #define maxn 605 #define INF 0x3f3f3f3f using namespaceView Codestd; typedef long long ll; int num[maxn],dis[maxn],path[maxn],pnum[maxn],vis[maxn]; int ma[maxn][maxn]; int n,m,s,d,u,v,w; int cnt[maxn]; void dijkstra() { memset(vis,0,sizeof(vis)); memset(cnt,0,sizeof(cnt)); for(int i=0;i<n;i++) dis[i]=INF; dis[s]=0; path[s]=-1; pnum[s]=1; cnt[s]=num[s]; for(int i=0;i<n;i++) { int t,minn=INF; for(int j=0;j<n;j++) { if(!vis[j]&&dis[j]<minn) { t=j; minn=dis[j]; } } vis[t]=1; for(int j=0;j<n;j++) { if(dis[j]>dis[t]+ma[t][j]) { dis[j]=dis[t]+ma[t][j]; path[j]=t; cnt[j]=cnt[t]+num[j]; pnum[j]=pnum[t]; } else if(dis[j]==dis[t]+ma[t][j]) { pnum[j]+=pnum[t]; if(cnt[j]<cnt[t]+num[j]) { cnt[j]=cnt[t]+num[j]; path[j]=t; } } } } } void print(int x) { if(path[x]==-1) { printf("%d",x); return; } print(path[x]); printf(" %d",x); return; } int main() { scanf("%d%d%d%d",&n,&m,&s,&d); memset(ma,INF,sizeof(ma)); for(int i=0;i<n;i++) scanf("%d",&num[i]); for(int i=0;i<m;i++) { scanf("%d%d%d",&u,&v,&w); ma[u][v]=w; ma[v][u]=w; } dijkstra(); printf("%d %d\n",pnum[d],cnt[d]); print(d); return 0; }
L2-001 緊急救援