PAT 甲级 1003 Emergency (DFS+最短路径)(c++版)(附代码注释)(附题意分析)

1003 Emergency (25 分)

原文链接:http://kakazai.cn/index.php/Kaka/Pat/query/id/93

题目

题目链接:https://pintia.cn/problem-sets/994805342720868352/problems/994805523835109376

As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.

Input Specification:

Each input file contains one test case. For each test case, the first line contains 4 positive integers: N (≤500) - the number of cities (and the cities are numbered from 0 to N−1), M - the number of roads, C1 and C2 - the cities that you are currently in and that you must save, respectively. The next line contains N integers, where the i-th integer is the number of rescue teams in the i-th city. Then M lines follow, each describes a road with three integers c1, c2 and L, which are the pair of cities connected by a road and the length of that road, respectively. It is guaranteed that there exists at least one path from C1 to C2.

Output Specification:

For each test case, print in one line two numbers: the number of different shortest paths between C1 and C2, and the maximum amount of rescue teams you can possibly gather. All the numbers in a line must be separated by exactly one space, and there is no extra space allowed at the end of a line.

Sample Input:

5 6 0 2
1 2 1 5 3
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 1

Sample Output:

2 4

题意分析

  • 题意

现在有一个城市群,某些城市之前有路径,路径长短不一。每个城市都有救援人员数。现在给定起点城市和终点城市,要求从起点城市出发,以最短的距离到达终点城市,这样的最短路径有多少条?最短路径中,救援人数的最大值是多少?

  • 分析

将城市看成点,路径看成边。用深度遍历求出从起点到终点所有可能的路径,取其最小值。同时,在最短路径中,记录救援人数的最大值。

知识点与坑点

  • 知识点

1)DFS

  • 坑点

1)

一、DFS

算法思路

1 从起点出发,用DFS求出到终点所有可能的路径。要注意,在具体的某条路径上,为了避免形成环,每个点只能访问一次。但在不同路径上,有些点是可以不止一次访问的。

2 遍历的同时,要保存好每条路径的总长度,和总救援人数。

3 不断更新最短路径,最短路径数目,总救援人数最大值,并按要求输出

代码-c++版

#include<cstdio>
using namespace std;
const int maxn = 510;//图中,所有点的编号范围
const int INF = 1000000000;

/* 关键变量 */ 
int edge[maxn][maxn];//边的长度
int v[maxn];//记录点是否被访问过
int men[maxn];//点的属性:救缓人数 
int s, d;//s出发,到d去
int n,e;//顶点数,边数

/*DFS:从起点出发,遍历所有可能的路径,到达终点*/ 
int shortest_length = INF;  //最短路径的长度
int shortest_num = 1;	//最短路径的数量 
int max_men = 0;	//最多救援人员数 
void DFS(int cur, int cur_length, int cur_men) {
//cur=当前路径上的终点;cur_length = 当前路径的长度;cur_men = 当前路径的救援人员数 

  /*剪枝*/
  if (cur_length > shortest_length)return; //当前路径长度已经大于最短路径,结束遍历 
  
  /*从起点到终点的路径*/
  if (cur == d) {	//到达终点d
    if (cur_length < shortest_length) {	//当前路径更短 
      shortest_length = cur_length;	//更新最短路径长度 
      shortest_num = 1;	//更新最短路径数目 
      max_men = cur_men;	//更新救援人数 
    }
    else if (cur_length == shortest_length) {//长度同等 
      shortest_num++;	//更新最短路径数目 
      if (cur_men > max_men) {	//救援人数更多,则更新 
        max_men = cur_men;
      }
    }
    return;
  }
  
  /*从cur出发,访问所有可能路径*/
  v[cur] = 1;//cur已经访问过
  for (int i = 0; i < n; i++) {
    if (v[i] == 1 || edge[cur][i] == 0)continue;
    DFS(i, cur_length + edge[cur][i], cur_men + men[i]);
  }
  
  /*从其他结点出发,能够访问cur*/
  v[cur] = 0;
}



int main() {
  
  scanf("%d %d %d %d", &n, &e, &s, &d);
  
  /* 每个城市的可调用的救援人员数*/
  for (int i = 0; i < n; i++) {
    scanf("%d", &men[i]);
  }
  
  /* 每个城市之间的路径长度*/
  for (int i = 0; i < e; i++) {
    int in1, in2, in3;
    scanf("%d %d %d", &in1, &in2, &in3);
    edge[in1][in2] = edge[in2][in1] = in3;
  }
  
  /*遍历各种从起点到终点的路径*/
  DFS(s, 0, men[s]);	//s起点是当前路径的终点,0是当前路径的长度,men[s]是路径的救援人员数 
  
  /*输出最短路径的数目,最短路径上救援人数的最大值*/
  printf("%d %d\n", shortest_num, max_men);
  
  return 0;
}

代码-python版


  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值