甲级PAT1003 Emergency(解坑)

1003 Emergency (25)(25 分)

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), 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

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

第一点(关键):一定要理解对题目的意思!!一直想了很久感觉自信满满的时候发现怎么提交除了示例答案对之外,其他测试全是答案错误。。原来坑在我没有理解题目的意思。这题是找到最短的路,并输出最短路径的条数和在其中某一路径上最大的团队数。而我理解为找到最短的路,并输出最短路径的距离和所有最短路径上的团队数之和(可能当时看题的时候还没睡醒。。。求大佬们不要喷,小萌新瑟瑟发抖)

顺便贴一下我理解题目意思的代码(应该是没有问题的,仅个人观点,利用了集合,以后可能会派上用场):

#include<iostream>
#include<cstring> 
#include<set>
using namespace std;

#define INF 99999
#define Ncity 501
#define Nroad 10000

int team[Ncity];
int road[Ncity][Ncity];
int dst[Nroad];
int book[Ncity];
set<int> s[Ncity];


//将B集合的元素合并至A集合中
void Union(set<int> &A,set<int> &B){
    set<int>::iterator it;
 
    it = B.begin();
    while(it != B.end()){
        A.insert(*it);
        it++;
    }
}


int main(){
	int N,M,C1,C2;
	cin>>N>>M>>C1>>C2;
	int i,j,k,u,min,maxteam;
	
	//初始化
	for(i = 0; i < N; i++){
		for(j = 0; j < N; j++){
			if(i==j){
				road[i][j]=0;
			}else{
				road[i][j] = INF;
			}
			
		}
	}
	maxteam = 0;
	memset(book,0,sizeof(book));
	for(i = 0; i < N; i++){
		cin>>team[i];
	}
	for(i = 1; i<= M;i++){
		cin>>j>>k;
		cin>>road[j][k]; 
	}

	for(i = 0; i < N; i++){
		dst[i]=road[C1][i];
		s[i].insert(i);
		if(dst[i]!=INF){
			s[i].insert(C1);
		}
	}
	book[C1] = 1;
	for(i = 1; i < N; i++){
		min = INF;
		for(j = 0; j < N; j++){
			if(book[j] == 0 && dst[j] < min){
				min = dst[j];
				u = j;
			}
		}
		book[u] = 1;
		for(k = 0; k < N; k++){
		   if(road[u][k]<INF && book[k]==0){
			   if(dst[k] > dst[u]+road[u][k]){
				    dst[k] = dst[u] + road[u][k];
					s[k] = s[u];
					s[k].insert(k);
			   }else if(dst[k] == dst[u]+road[u][k]){
			   		Union(s[k],s[u]);
			   }
		   }
        }
	}
	
	
	set<int>::iterator it;
	for(it=s[C2].begin();it!=s[C2].end();it++){
		maxteam+=team[*it];
	}
    			
	cout<<dst[C2]<<" "<<maxteam;
	return 0;
} 

 

下面才是正片的开始:

首先是解题思路:这里用dijkstra方法求最短路径。

(dijkstra方法的整体思路是,将N个点分为两个集合(使用过的集合S1和未被使用过的集合S2),从起始点开始,将起始点加入使用过的集合S1,每次选所有与起始点连接路径最短的未被使用过点u,将点u加入使用过的集合S1,然后寻找对于未被使用集合S2中的点k是否有dst[u]+road[u][k]<dst[k],不断更新起始点到其他点的最短路径,经过N-1次,dst数组中存储的就是起始点到所有其他点的最短距离)

利用dst[i]数组保存起始城市C1到i的最短距离。book数组表示该城市是否已在使用过的集合中。在求最短路径的时候,要记录方法数和最大营救团队数。每次利用dijkstra方法的时候是根据来判断dst[u]+road[u][k]与dst[k]的值来判断是否是最短路径。

若dst[u]+road[u][k]<dst[k]成立,表示从起始城市->u->k是从起始城市到k的最短路径,对应的方法数为u的方法数,对应的最大营救团队数为u的最大营救团队数加上k的团队数。

若dst[u]+road[u][k]==dst[k]成立,则表示从起始城市->u->k另一种最短路径的方法。对应的方法数要加上u的方法数,然后判断起始城市->u->k该路径的最大营救团队数是否比之前的最大营救团队数多。哪个多就用哪个。

坑1.计算最大营救团队数时,初始时,起始城市只加一次,其他与起始城市连接的城市要加起始城市的营救团队。

	for(i = 0; i < N; i++){
		maxteam[i] = team[i];
		if(dst[i]!=INF&&i!=C1){
			maxteam[i]+=team[C1];	
		}
	}

坑2:该图是一个无向图,但是输入只输了一边,所以另一边也要赋值。就比如输入A->B的值,B->A的距离和A->B的距离是相等的,这是一个隐藏的条件。

解决了这两个坑代码终于通过了。。。。第一天题目意思理解错想了一天没结果。。第二天排坑。。找错误找半天。。不过还是很开心的(*^▽^*)

正确代码:

#include<iostream>
#include<cstring> 
using namespace std;

#define INF 99999
#define Ncity 501
#define Nroad 10000

int team[Ncity];
int road[Ncity][Ncity];
int dst[Nroad];
int book[Ncity];
int maxteam[Ncity];
int way[Ncity];


int main(){
	int N,M,C1,C2;
	cin>>N>>M>>C1>>C2;
	int i,j,k,u,min;
	
	//初始化
	for(i = 0; i < N; i++){
		for(j = 0; j < N; j++){
			road[i][j] = INF;	
		}
	}
	memset(book,0,sizeof(book));
	for(i = 0; i < N; i++){
		cin>>team[i];
	}
	for(i = 1; i<= M;i++){
		cin>>j>>k;
		cin>>road[j][k];
		road[k][j] = road[j][k];
	}

	for(i = 0; i < N; i++){
		dst[i]=road[C1][i];
		maxteam[i] = team[i];
		way[i] = 1;
		if(dst[i]!=INF&&i!=C1){
			maxteam[i]+=team[C1];	
		}
	}

	book[C1] = 1;
	for(i = 1; i < N; i++){
		min = INF;
		for(j = 0; j < N; j++){
			if(book[j] == 0 && dst[j] < min){
				min = dst[j];
				u = j;
			}
		}
		book[u] = 1;
		for(k = 0; k < N; k++){
		   if(road[u][k]<INF && book[k]==0){
			   if(dst[k] > dst[u]+road[u][k]){
				    dst[k] = dst[u] + road[u][k];
					maxteam[k] = maxteam[u] + team[k];
					way[k] = way[u];
			   }else if(dst[k] == dst[u]+road[u][k]){
			   		way[k] += way[u];
			   		if(maxteam[k] < maxteam[u]+team[k]){
			   			maxteam[k]=	maxteam[u]+team[k];			
					}
			   }
		   }
              }
	}	
	cout<<way[C2]<<" "<<maxteam[C2];
	return 0;
} 

 

 

点赞