问题:要求求出长度和最短路径长度相同的路径条数,和走这些路径时能聚集的人的最大数目。做这道题暴露出来一个问题:学知识过于死板,图论方面的知识还是只停留在会板子的阶段。一定要多想,多总结。
本题解法:涉及到了求最短路问题,自然能联想到用dijkstra算法,但本题要求的是长度等于最短长度的路径条数和最大人数,另设两个数组,记录最短路径条数和最大人数,并对原始dijkstra算法做小小的变形即可顺利AC
核心代码,松弛最短路时做出小小改变
for(int j=0;j<n;j++){
if(!vis[j]&&dis[flag]+mp[flag][j]<dis[j]){
dis[j]=dis[flag]+mp[flag][j];
w[j]=w[flag]+weight[j];
routes[j]=routes[flag];
} else if(!vis[j]&&dis[flag]+mp[flag][j]==dis[j]){
routes[j]+=routes[flag];//!!!!!!
w[j]=max(w[j],w[flag]+weight[j]);
}
}
其中,w数组中保存的时最大的人数,routes数组中保存的时最短路的条数,weight数组中保存的是该站的人数
解读:当flag可以松弛点j时,证明原来到点j的不是最短路,所以人数和路径条数必须使其等于w[flag]和routes[flag];当不能松弛但是两条路径长度正好相同时,证明路径条数增多了,此时必须使得routes[j]=routes[j]+routes[flag],同时因为要求的是最大的人数,所以w[j]=max(w[j],w[flag]+weight[j])
AC代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=505;
const int INF=0x3f3f3f3f;
int mp[maxn][maxn],dis[maxn],vis[maxn],routes[maxn],weight[maxn],w[maxn];
int n,m,c1,c2;
void init() {
for(int i=0; i<n; i++) {
for(int j=0; j<n; j++) {
if(i==j) mp[i][j]=0;
else mp[i][j]=INF;
}
}
}
void dijkstra(int st){
for(int i=0;i<n;i++){
dis[i]=mp[st][i];
w[i]=weight[i];
}
for(int i=0;i<n;i++){
int minn=INF,flag=-1;
for(int j=0;j<n;j++){
if(!vis[j]&&dis[j]<minn){
minn=dis[j];
flag=j;
}
}
if(flag==-1) break;
vis[flag]=1;
for(int j=0;j<n;j++){
if(!vis[j]&&dis[flag]+mp[flag][j]<dis[j]){
dis[j]=dis[flag]+mp[flag][j];
w[j]=w[flag]+weight[j];
routes[j]=routes[flag];
} else if(!vis[j]&&dis[flag]+mp[flag][j]==dis[j]){
routes[j]+=routes[flag];//!!!!!!
w[j]=max(w[j],w[flag]+weight[j]);
}
}
}
}
int main(){
int a,b,c;
cin>>n>>m>>c1>>c2;
init();
for(int i=0;i<n;i++){
cin>>weight[i];
}
for(int i=0;i<m;i++){
cin>>a>>b>>c;
mp[a][b]=mp[b][a]=mp[a][b]<c?mp[a][b]:c;
}
routes[c1]=1;
dijkstra(c1);
printf("%d %d\n",routes[c2],w[c2]);
return 0;
}