题意:给你n个城市,城市标号为0--n-1,它们之间由m条路相连通,给你出发点和终点。每个城市里面有救援队人数,,剩下的m行给出你路径的信息,为路径连接的城市标号和路径长度。要求到达终点的最短路径的路径数和一路上能获得的最大的救援队人数。
分析:标准最短路问题,不过需要统计路径数量和结点的一些信息,下面给出两个板子,一个针对本题,一个针对天梯赛紧急救援问题,两个题如出一辙,不过天梯赛的题还需要输出路径,仅此而已,设置一个数组记录每个城市的前驱结点就好了。
针对本题:
1 #include<iostream> 2 #include<algorithm> 3 #include<vector> 4 #include<cstring> 5 using namespace std; 6 int n,m,s,e; 7 int per[505];//各地救援队人数 8 int tol[505];//总救援人数 9 int dis[505];//各地距离 10 int vis[505];//是否访问过 11 int road[505];//到各地有多少条最短的路径 12 struct city 13 { 14 int e,len; 15 }; 16 vector<city> ve[505]; 17 18 void init() 19 { 20 memset(vis,0,sizeof(vis)); 21 memset(tol,0,sizeof(tol)); 22 memset(road,0,sizeof(road)); 23 for(int i=0;i<n;i++) 24 { 25 dis[i]=0x3f3f3f3f; 26 } 27 tol[s]=per[s]; 28 dis[s]=0; 29 road[s]=1; 30 } 31 32 void djst() 33 { 34 while(1) 35 { 36 int u=-1; 37 int maxx=0x3f3f3f3f; 38 for(int i=0;i<n;i++) 39 { 40 if(dis[i]<maxx&&vis[i]==0) 41 { 42 u=i; 43 maxx=dis[i]; 44 } 45 } 46 if(u==-1) 47 { 48 break; 49 } 50 vis[u]=1; 51 for(int i=0;i<ve[u].size();i++) 52 { 53 int v=ve[u][i].e; 54 if(vis[v]==0) 55 { 56 if(dis[v]>dis[u]+ve[u][i].len) 57 { 58 dis[v]=dis[u]+ve[u][i].len; 59 tol[v]=tol[u]+per[v]; 60 road[v]=road[u]; 61 } 62 else if(dis[v]==dis[u]+ve[u][i].len) 63 { 64 road[v]+=road[u]; 65 if(tol[v]<tol[u]+per[v]) 66 { 67 tol[v]=tol[u]+per[v]; 68 } 69 } 70 } 71 } 72 } 73 } 74 75 int main() 76 { 77 while(cin>>n>>m>>s>>e) 78 { 79 for(int i=0;i<n;i++) 80 { 81 cin>>per[i]; 82 } 83 for(int i=0;i<m;i++) 84 { 85 int x,y,l; 86 cin>>x>>y>>l; 87 city temp1,temp2; 88 temp1.e=y,temp1.len=l;//无向图存储 89 ve[x].push_back(temp1); 90 temp2.e=x,temp2.len=l; 91 ve[y].push_back(temp2); 92 } 93 init(); 94 djst(); 95 cout<<road[e]<<" "<<tol[e]<<endl; 96 } 97 return 0; 98 }
天梯赛:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <vector> 6 #include <stack> 7 using namespace std; 8 const int maxn=505; 9 const int INF=0x3f3f3f3f; 10 int n,m,s,d; 11 int per[maxn]; //救援人数 12 int dis[maxn]; //距离起点最短距离 13 int vis[maxn];//是否列入集合 14 int road[maxn];//最短路径条数 15 int path[maxn];//前缀节点 16 int tol[maxn];//总救援人数 17 struct city 18 { 19 int e; 20 int len; 21 }; 22 vector <city> ve[maxn]; 23 //初始化 24 void init () 25 { 26 memset (vis,0,sizeof(vis)); 27 memset (tol,0,sizeof(tol)); 28 memset (road,0,sizeof(road)); 29 memset (path,-1,sizeof(path)); 30 for (int i=0;i<n;i++) 31 dis[i]=INF; 32 dis[s]=0; 33 tol[s]=per[s]; 34 road[s]=1; 35 } 36 void djst () 37 { 38 while (1) 39 { 40 int maxx=INF; 41 int u=-1; 42 for (int i=0;i<n;i++) 43 if(dis[i]<maxx&&!vis[i]) 44 { 45 maxx=dis[i]; 46 u=i; 47 } 48 if(u==-1)//如果u依旧还是等于-1说明全部点都已经最小了,循环结束 49 break; 50 vis[u]=1;//不然以u点作为中介来向周围扩展 51 for (int i=0;i<ve[u].size();i++) 52 { 53 int v=ve[u][i].e;//以u点通过u点的边能找到v点,从而扩散v点 54 if(!vis[v])//如果v点还没访问过 55 { 56 if(dis[v]>dis[u]+ve[u][i].len)//如果直接到v点比通过u到达v更远,则更新一下 57 { 58 dis[v]=dis[u]+ve[u][i].len; 59 path[v]=u;//记录一下路径,到v的前驱是u 60 road[v]=road[u];//到v的最短路径与到u的最短路径条数一样 61 tol[v]=tol[u]+per[v];//到v的救援人数是到u的人数+v的救援人数 62 63 } 64 else if(dis[v]==dis[u]+ve[u][i].len)//如果直接到V和通过u到v的长度一样 65 { 66 //这里要写到if语句外面 67 road[v]+=road[u];//那到v的最短路径数就要加上到u的最短路径条数 68 if(tol[u]+per[v]>tol[v])//更新救援人数和路径,因为题目中救援人数是第二关键字 69 { 70 path[v]=u;//如果可以更新,那么v的前驱就必须是u 71 tol[v]=tol[u]+per[v]; 72 } 73 } 74 } 75 } 76 } 77 } 78 //输出函数 79 void output() 80 { 81 printf("%d %d\n",road[d],tol[d]); 82 int temp=d; 83 stack<int>ss; 84 while (path[temp]!=-1) 85 { 86 ss.push(temp); 87 temp=path[temp]; 88 } 89 ss.push(s); 90 while (!ss.empty()) 91 { 92 printf("%d%c",ss.top(),ss.size()==1? '\n':' '); 93 ss.pop(); 94 } 95 } 96 int main() 97 { 98 scanf("%d%d%d%d",&n,&m,&s,&d); 99 for (int i=0;i<n;i++) 100 scanf("%d",&per[i]); 101 init(); 102 for (int i=0;i<m;i++) 103 { 104 int x,y,len; 105 scanf("%d%d%d",&x,&y,&len); 106 city temp1,temp2; 107 temp1.e=y; temp1.len=len; 108 temp2.e=x; temp2.len=len; 109 ve[x].push_back(temp1);//无向图 110 ve[y].push_back(temp2); 111 } 112 djst(); 113 output(); 114 return 0; 115 }