PAT1003
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
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),
第一行包含四个正整数,N表示城市的数量
M - the number of roads, C1 and C2 - the cities that you are currently in and that you must save, respectively.
M表示路的数量,C1和C2分别表示你当时在的城市和你需要救援的城市。
The next line contains N integers, where the i-th integer is the number of rescue teams in the i-th city.
下一行包含N个整数,第I个整数表示在第I个城市救援队的数量。
Then M lines follow, each describes a road with three integers c1, c2 and L,
下面接着M行,每一行用三个整数c1、c2、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.
C1和C2之间保证存在至少一条路径
Output
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.
不同的C1和C2的最短路的条数,和能集合的最大的救援队的数量。
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
一看到是最短路径的题目就眼前一亮,脑子里面应该马上浮现出那几种方法。
首先一上来就是最简单的floyd,但是一看数量级500,N^3就不得了了,然后求的也不是任意两点都要求距离,所以不适用。
那么简单一点就是用dijkstar。
然后就死了。。。。。为什么呢?因为做过太多的题目,都是让你求两点间的最短路径,但是这道题目偏偏不是,它是让你求出最短路径的条数,而不是最短路径的长度。
所以一上来就死了,我一直求出的第一个结果都是dis【】,然后给出的测试用例又是正确的,真的是,哎。
那么就有人会问了,那么让你求出最短路径的条数,怎么求呢?还有救援队的最大值呢?
这里我就要多说一下了,这道题目需要比较深刻的理解dijkstar的算法,然后合理的运用它的思想去解决这两个问题。
dijkstar在计算最短路径的时候,利用一个数组存放源点到任意点的距离。然后利用寻找到的当前的确定值,去松弛每一个估计值。
我们可以利用这一思想去解决我们的问题。下面的代码中,我使用teamDis2数组保存最短路径的数目当if(dis[i] > dis[index] + maps[index][i])出现的时候,证明可以松弛了,就代表需要更新路径,那么当前路径的最小值就是目标路径的最小值。当else if(dis[i] == dis[index] + maps[index][i])出现的时候,证明这两条路径均可以到达目标点,且距离相同,则最小路径为两者之和。
我使用teamDis1数组保存最大的救援队数目
当if(dis[i] > dis[index] + maps[index][i])出现的时候,证明可以松弛了,就代表需要更新路径,那么救援队的数目需要像dis距离一样变动。当else if(dis[i] == dis[index] + maps[index][i])出现的时候,证明这两条路径均可以到达目标点,且距离相同,那么救援队的数目需要取两条路径的最大值。
这两个子问题都是依靠dijkstar的思想解决的,需要仔细的思考一下。慢慢体会一下。
#include<cstdio> #include<cstdlib> #include<iostream> #include<algorithm> #include<string.h> using namespace std; /* dijkstra */ int maps[500][500];//用于记录路径 int team[500]; int dis[500]; int teamDis1[500]; int teamDis2[500]; int book[500]; const int MAX = 0x7ffffff; int main() { int i,j,q,c1,c2; int city,roads,starting,ending; int index,indexNumber;//离当前点最近的点的坐标和坐标 cin>>city>>roads>>starting>>ending; //初始化dis数组 for (i = 0; i < city; i++) dis[i] = MAX; //初始化maps数组 for (i = 0; i < city; i++) for (j = 0; j < city; j++) if(i != j) maps[i][j] = MAX; else maps[i][j] = 0; for (i = 0; i < city; i++) { cin>>team[i]; } for (i = 0; i < roads; i++) { cin>>c1>>c2; cin>>maps[c1][c2]; maps[c2][c1] = maps[c1][c2];; if(c1 == starting) { dis[c2] = maps[c1][c2]; } else if(c2 == starting) { dis[c1] = maps[c1][c2]; } } dis[starting] = 0; teamDis2[starting] = 1; teamDis1[starting] = team[starting]; for (q = 0; q < city; q++) { index=0; indexNumber = MAX; for (i = 0; i < city; i++) { if(book[i] == 0 && dis[i] < indexNumber) { indexNumber = dis[i]; index = i; } } book[index] = 1; for (i = 0; i < city; i++) { if(book[i] == 0 && maps[index][i] != MAX) { if(dis[i] > dis[index] + maps[index][i]) { dis[i] = dis[index] + maps[index][i]; teamDis1[i] = teamDis1[index] + team[i]; teamDis2[i] = teamDis2[index]; } else if(dis[i] == dis[index] + maps[index][i]) { teamDis2[i] += teamDis2[index]; if(teamDis1[i] < teamDis1[index] + team[i]) teamDis1[i] = teamDis1[index] + team[i]; } } } if(index == ending) break; } cout<<teamDis2[ending]<<" "<<teamDis1[ending]<<endl; return 0; }