【PAT甲级】 1003 Emergency
原题
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 1:
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 1:
2 4
思路
题目要求
给出城市数、城市间的道路数、各城市的救援队伍、城市间各道路连接的具体城市和长度,求给定两个城市之间的最短路径长度以及能召集到的最大救援队伍数。
题目分析
- 输出只有两个数中间有一个空格;
- 输出为一行;
- 最短距离基本上的第一想法就是Dijkstra;
易错点
- 输出的不是最短路径长度,而是最短路径数量;
- 最大救援队伍是在最短路径的基础上的,并不是对于所有可到达路径而言;
参考代码如下
#include <iostream>
#include <string.h> //memset头文件
#define N 502 //不能用typedef 1000 N啊
const int inf = 99999999;
int main(){
int n,m,start,end;//第一行的输入
int team[N];//救援队伍的个数
int road[N][N];//各城市连接道路的长度
memset(road,0x3f,sizeof(road));//赋值为无穷远
int num[N];//到i的最短路径条数
int dis[N];//到i的最短路径长度
memset(dis,0x3f,sizeof(dis));
int sum[N];//到i的救援队数量
bool visit[N];//判断该距离是否固定
memset(visit,0,sizeof(visit));//尝试了一下好像默认赋值就是0
scanf("%d %d %d %d",&n,&m,&start,&end);
int i,j;
for(i=0;i<n;i++){
scanf("%d",&team[i]);
}
for(i=0;i<m;i++){
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
road[a][b]=c;
road[b][a]=c;
}
dis[start]=0;//到自己的距离为0
sum[start]=team[start];
num[start]=1;//直接可以到自己
for(i=0;i<n;i++){
int ii=-1;
int minn=inf;
for(j=0;j<n;j++){
if(visit[j]==0 && dis[j]<minn){ //保留未确定的最小值
minn = dis[j];
ii = j;
}
}
if(ii==-1) break;
visit[ii]=1;
for(j=0;j<n;j++){
if(visit[j]==0 && road[ii][j]!=inf){ //根据最近的点去更新其他未确定的点
if(dis[ii]+road[ii][j]<dis[j]){
dis[j]=dis[ii]+road[ii][j];
num[j]=num[ii];
sum[j]=sum[ii]+team[j];
}
else if(dis[ii]+road[ii][j]==dis[j]){ //说明直达和经过ii点距离一样
num[j]+=num[ii];
if(sum[j] < sum[ii]+team[j]) sum[j]=sum[ii]+team[j];
}
}
}
}
printf("%d %d",num[end],sum[end]);
return 0;
}
fill && memset
用法
fill
- 按照单元赋值,将某个区间的元素都赋予val值;
#include <algorithm> //头文件
fill(vec.begin(), vec.end(), val);
memset
- 按照字节填充某字符;
#include <cstring> //头文件
const int INF = 0x3f3f3f3f;
memset(a,INF,sizeof(a));
区别
- 赋值元素
- 因为memset函数按照字节填充,所以一般memset只能用来填充char型数组;
- 如果填充int型数组,只能填充0、-1 和 inf(正负都行);
- 要把一段内存全部置为无穷大,memset(a,0x3f,sizeof(a));
- 无穷小可以设为0x8f;
- 而fill可以按照自己的想法在任意部位填充值;
- 运行效率
- 我查找到的资料是说memset要比fill处理速度更快一些;
- 在可以满足条件的情况下推荐用memset
附
- 网上的参考代码很多;
- 以上仅是用来记录我个人的想法和答题方式;
- 仅为入门选手,如有错误或者更好的方法欢迎指正与探讨;
- 该代码基本和算法书上有关Dijkstra这一块代码的相同,若看不懂可以直接看书;