多说无益,代码走起。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxv=510;
const int inf=1000000000;
int path[510];
int n,m,c1,c2,g[maxv][maxv],weight[maxv],j;
int d[maxv],w[maxv],num[maxv];
bool vis[maxv]=//是否访问 (是否到达过)
void dijkstra(int s){
fill(d,d+maxv,inf);//最短路径的长度
memset(num,0,sizeof(num));//最短路径的数量
memset(w,0,sizeof(w));//物资的数量
d[s]=0;
w[s]=weight[s];
num[s]=1;
for(int i=0;i<n;++i){
int u=-1,min=inf;
for(int j=0;j<n;++j){
if(vis[j]==false&&d[j]<min) {
u=j;min=d[j];}
}
if(u==-1) return;
vis[u]=true;
for(int v=0;v<n;++v){
if(vis[v]==false&&g[u][v]!=inf){
if(d[u]+g[u][v]<d[v]) {
path[v]=u;
d[v]=d[u]+g[u][v];
w[v]=w[u]+weight[v];
num[v]=num[u];
}
else if(d[u]+g[u][v]==d[v]){
if(w[u]+weight[v]>w[v]) {
path[v]=u;w[v]=w[u]+weight[v];}
num[v]+=num[u];
}
}
}
}
}
void pathprint(int x){
if(path[x]==c1) {
printf("%d",c1);return;}
else {
pathprint(path[x]);printf(" %d",path[x]);}
}
int main()
{
cin>>n>>m>>c1>>c2;
for(int i=0;i<n;++i){
cin>>weight[i];
}
int u,v;
fill(g[0],g[0]+maxv*maxv,inf);
for(int i=0;i<m;++i){
cin>>u>>v;
cin>>g[u][v];
g[v][u]=g[u][v];
}
dijkstra(c1);
cout<<num[c2]<<" "<<w[c2]<<endl;
pathprint(c2);
printf(" %d\n",c2);
return 0;
}
题解之还是不读题
求一个最短路径的问题,但是这个需要统计最短路径的条数,还要找到物资(救援队)最大的那一个,并且输出最短路径。现在再看这道题,就是先以 Dijkstra算法为基础,之后慢慢地往里边添加条件。
//这是题头
const int maxv=510;//结点的数量最大值
const int inf=1000000000;//一个很大的数字,为了比较两点间的距离
核心:Dijkstra算法
为解决最短路径而生,我是从《算法笔记》学到的,大致会一样。我注释掉的就是自己添加的
int n,g[maxv][maxv];
int d[maxv];
bool vis[maxv];
void dijkstra(int s){
fill(d,d+maxv,inf);//最短路径的长度
//memset(num,0,sizeof(num));最短路径的数量
//memset(w,0,sizeof(w));物资的数量
d[s]=0;//s为起点,所以到达s的距离就是0
//w[s]=weight[s];
//num[s]=1;
for(int i=0;i<n;++i){
int u=-1,min=inf;
for(int j=0;j<n;++j){
if(vis[j]==false&&d[j]<min) {
u=j;min=d[j];}
}//该点未被访问过,且能到达 继续
if(u==-1) return;//没有 退出
vis[u]=true;
for(int v=0;v<n;++v){
if(vis[v]==false&&g[u][v]!=inf){
//寻找未被访问8*的点且有通路,
if(d[u]+g[u][v]<d[v]) {
d[v]=d[u]+g[u][v];//找到长度最小的点,并更新到起点的距离
//path[v]=u;
//w[v]=w[u]+weight[v];
//num[v]=num[u];
}
/*else if(d[u]+g[u][v]==d[v]){距离如果相等,这是后话
if(w[u]+weight[v]>w[v]) {
path[v]=u;
w[v]=w[u]+weight[v];}
num[v]+=num[u];
}*/
}
}
}
}
拼图:最短路径的数量和物资的多少
题目条件在最短路径的前提下找到最多的救援队。在Dijkstra函数中添加以下内容。
memset(num,0,sizeof(num));//最短路径的数量
memset(w,0,sizeof(w));//物资的数量
w[s]=weight[s];
num[s]=1;
vis[u]=true;
for(int v=0;v<n;++v){
if(vis[v]==false&&g[u][v]!=inf){
if(d[u]+g[u][v]<d[v]) {
//如果找到了距离较小的点
//path[v]=u;还没轮到他,一会再说
d[v]=d[u]+g[u][v];//更新该点长度
w[v]=w[u]+weight[v];//更新该点物资
num[v]=num[u];//更新能到达该点的数量
}
else if(d[u]+g[u][v]==d[v]){
//如果长度相等
if(w[u]+weight[v]>w[v]) {
//但物资更多
//path[v]=u;同上
w[v]=w[u]+weight[v];}//更新该点的物资
num[v]+=num[u];//无论物资怎样,但长度相同 所以能到达u的就能到达v。更新最短路径数量
}
}
}
拼图:输出路径
最后一个,输出路径,
int path[510];//这个存的是 每一个结点如果按最短路径走的前一个结点是谁
void pathprint(int x){
//一个小递归
if(path[x]==c1) {
printf("%d",c1);return;}//走到起点就结束
else {
pathprint(path[x]);printf(" %d",path[x]);}
}
path[v]=u;//在上一个拼图里有的两条相同语句,意思是找到长度较小的点时,更新它的前一个点
小细节
因为题目说道路。所以是双向路径
for(int i=0;i<m;++i){
cin>>u>>v;
cin>>g[u][v];
g[v][u]=g[u][v];
}
记得最后输出终点
printf(" %d\n",c2);
有了核心和一系类的夺冠拼图,在注意一下小细节 你就是总冠军。
wish you all the best.