PTA 数据结构与算法编程集 35-7-35 城市间紧急救援 (25 分)

7-35 城市间紧急救援 (25 分)作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。
输入格式:
输入第一行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0 ~ (N−1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。
第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。
输出格式:
第一行输出最短路径的条数和能够召集的最多的救援队数量。第二行输出从S到D的路径中经过的城市编号。数字间以空格分隔,输出结尾不能有多余空格。
输入样例:
4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2

输出样例:
2 60
0 1 3

思路:很容易想到用Dijkstra算法去解决,但是我在代码实现过程中碰了很多壁。
在《数据结构与算法分析》的书上对于Dijkstra算法的描述是:

在每个阶段,Dijkstra算法选择一个顶点v,它在所有未知的顶点中具有最小的d(v),同时算法声明从s到v的最短路径是已知的,阶段的其余部分有d(w)值的更新工作组成。//顶点选好后开始对这个顶点的邻近点的最短路径进行优化(也就是对d(w)的值进行更新,使得起始点到w点的路径最短)

#include<iostream>
#include<cstring>
using namespace std;
const int inf = 0xffffff;
struct Node
{
 int known;
 int dist;
 int currc;    
 int rc;
};
int N,M,S,D,cnt[510],maxl = 1;
int path[510],d[510][510];
Node city[510];
void initial()
{
 for(int i=0;i < N;i++){ 
  int rc;
  cin >> rc;
  city[i].currc = rc;    //从起始点到i聚集到的救援队数量
  city[i].rc = rc;	//i城市的救援队数量
  cnt[i] = 1;		//从起始点到i的最短路径条数
 }
 for(int i=0;i < N;i++){
  city[i].known = 0;		//初始状态顶点i设为未知
  city[i].dist = inf;	    //起始点到i的距离设为无限大
 }
 city[S].dist = 0;
 for(int i=0;i < N;i++){
  for(int j=0;j < N;j++){
   if(i != j)
    d[i][j] = d[j][i] = inf + 1;
  }
 }
 for(int i=0;i < M;i++){
  int u,v,l;
  scanf("%d%d%d",&u,&v,&l);
  d[u][v] = d[v][u] = l;
 }
}
int findmin()
{
 int minl = inf,mini;
 for(int i=0;i < N;i++){
  if(!city[i].known){
   if(city[i].dist < minl){
    minl = city[i].dist;
    mini = i;
   }
  }
 }
 return mini;
}
void dijkstra()
{
 int st = findmin();  //找出所有未知顶点中离起始点路径最短的点
 if(st != D){
  city[st].known = 1;
  for(int i=0;i < N;i++){
   if(!city[i].known){
    if(city[st].dist + d[st][i] < city[i].dist){ //更新
     city[i].dist = city[st].dist + d[st][i];
     city[i].currc = city[st].currc + city[i].rc; // 1
     path[i] = st;
     cnt[i] = cnt[st]; // 2.1,// 更新最短路径条数
    }
    else if(city[st].dist + d[st][i] == city[i].dist){
      cnt[i] += cnt[st];   //2.2
      if(city[st].currc + city[i].rc > city[i].currc){
       city[i].currc = city[st].currc + city[i].rc;
       path[i] = st;
      }
    }
   }
  }
  dijkstra();
 }
}
/*void findmax(int p)
{
 if(p != S){
  maxl *= cnt[p];
  findmax(path[p]);
 }
 else
  return;
}*/
void printpath(int p)  //打印路径
{
 if(p != S){
  printpath(path[p]);
  printf(" %d",p);
 }
 else
  printf("%d",S);
}
int main()
{
 cin >> N >> M >> S >> D;
 initial();
 dijkstra();
 //findmax(D);
 cout << cnt[D]<< " " << city[D].currc << endl;
 printpath(D);
 return 0; 
}

上面的1,2处的代码,是参照别人的想法写的,我原来写的会出错,只能通过0,2两个测试点,然后绞尽脑汁的想,自己设计数据,然而还是没调试对,然后去和别人的代码做对比,然后一点一点的发现错误:

1处的原代码为:

city[i].currc += city[st].currc;

错误点:虽然一开始 city[i].currc 会等于 city[i].rc 但是在顶点 i 的最短路径更新后,city[i].currc 就不等于 city[i].rc 了,当时想当然了。

2处原代码:

 cnt[i] = 1;  //2.1处  更新最短路径后i顶点的最短路径条数为1
 cnt[i]++;  //2.2处出现相同的最短路径是i顶点的最短路径加一

顶点全部遍历完后再调用findmax将最短路径上的cnt[i]值全部相乘,最后得到最短路径条数。
当时我是觉得很有道理的(哈哈),但是和别人的代码对比,虽然表现算法的形式不同,但是算法思想是一致的,只有这两处的代码和别人的格格不入。这里错在只能算到有最多救援队数量的最短路径条数,其他虽然也是最短路径但是救援队数量少的而无法遍历到,造成漏解。

猜你喜欢

转载自blog.csdn.net/qq_43189757/article/details/88735617