PTA团体程序设计天梯赛 L2-001 紧急救援

多说无益,代码走起。

#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.

Guess you like

Origin blog.csdn.net/M1170780140/article/details/104910075