pat1003

19 篇文章 0 订阅
16 篇文章 0 订阅

1003. Emergency (25)

时间限制
400 ms
内存限制
32000 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

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
这道题基于的算法思想是DFS的搜索方式,注释明天在详细的写上 ,先来把代码贴一下。
这里的变量说明是这样的,其中vexnum 是用来记录图中的顶点个数的,arcnum 是用来记录图中边的个数的变量。
start 用来记录开始顶点的序号,end 用来标示目的点的顶点序号。
map 二维数组用来存放图中的边是作为邻接矩阵而存在的,weight 用来存放每个顶点上的权值大小,visited 是用来
记录题目中[0..vexnu-1]个顶点中每个顶点是否被访问过的表示符号的。
sPath 是用来记录(并且如果图中存在没有访问的顶点,也是在不断更新的)图中最短路径的长度的。
nWei 是用来记录从起始点 start 到目的顶点 end 的所有的最短路径中,经过顶点对应权值最大的值,
同 sPath 变量的更新方式类似,只要是图中还存在没有访问过的顶点,nWei 的数值也是不断更新的。
counter 这个变量是用来记录从起始顶点 start 到目的顶点 end 之间的最小路径的数目。
void inPut() :
这个方法主要是用来对图中的属性数据结构进行初始化,和接收来自题目的数据的。初始化比如说将邻接矩阵中的任意两点
之间的距离设定为无穷大,用来表示的是初始条件下任意两点之间都是不连通的。 或是将用来表示图中顶点是否被访问过的
visited[0..vexnum-1] 数组中的数值全部置为 0 ,用以表示在初始条件下,图中的任何顶点都是未被访问的。
初始化数据之后,接下来要根据题中输入的数据来对图中的各个属性数据结构进行赋值,
首先,得到的是顶点的数目,和图中边的总数以及最短路径的起始点和终点的顶点坐标。
然后,再通过循环得到图中两点之间的连通情况和两点之间的边所对应的权值,并将其数值存放于邻接矩阵中。
 
 
void dfs( curPoin , target , curPath ,curWei)
这个方法才是本题目中的核心所在,其中方法中的四个参数分别代表的含义是,当前所访问到的顶点编号 curPoint,
以及最短路径所通向的终点的位置坐标:target,当前所记录的最短路径的局部最短路径距离 curPath, 和当前所记录的走过的所有最短路径中
所记录的局部最大顶点权值 curWei 。
 在每一次进入方法中以后,首先会判断当前的顶点是否就是最短路径所需要通向的目的顶点坐标 即 curPoint== target,如果是的话,把当前所记录的最短路径的距离值
与记录在全局变量中的sPath 所对应的距离值进行比对,如果当前距离数值比较小的话,则将 curPath ->sPath ,并且用来记录最短路径个数
的counter 要重新置值为 1 ,因为这个时候由于拓展到了新的距离目的顶点的路径距离更短,所以之前记录的局部最短路径并不是全局的最短
路径,所以计数器的数值也变成没有意义的计数。 所以将数值置为 1 重新计数,并同时将记录最短路径通过的各个顶点的权值都修正为当前顶点权值。
因为最短路径都变得更小,所以当前求得的最短路径所通过的顶点必定与之前的最短路径所通过的顶点是由很多不同的。
如果在条件 target = curPoint 下,存在当前最短路径长度与全局最短路径长度是相同的,那么接下来就要比较一下当前顶点权值curWei 
和全局最短路径上所经过顶点权值 nWei 的大小。如果 curWei > nWei 的话,则将 nWei 的数值更新为 curWei的数值。 
对应的 dfs 是一个递归的操作,在访问某一个顶点之前将访问标志数组对应该顶点编号置为 1 即已访问过,
如果所走的这条路径不满足的话,dfs 会进行 return 操作,所以会返回到递归的上一层,所以在递归调用的下面一条语句
对应的是递归访问之后的后续处理操作的位置,将 visited 数组中的该顶点对应的访问状态重新置为未访问过即可,这里表示的是
上一步所走的路线一直到目标顶点之后对应的其余状态数值并不满足题意,所以回溯到上一步还没有开始的状态重新选择一个一个方向走下去。
 
 
而对于将 curPath > sPath 的情形直接return 是因为,在 目标顶点与起始点并不重合的情况下,当前路径的长度都已经大于已经求得的
局部路径的长度的话,就没有必要继续向下搜索下去了, 直接将状态空间树中的对应这一分支进行剪枝处理,这样就不用继续向下判断了。
#include <cstdio>
#include <cstdlib>

#define MAXN 505 
#define INF_MAX 100000

int vexnum , arcnum,start , end ;
int map[MAXN][MAXN] ,weight[MAXN],visited[MAXN] ;
int sPath , nWei,counter = 0 ;

void inPut ( )
{
	int from , to , w;

	scanf("%d%d%d%d",&vexnum, &arcnum, &start, &end) ;

	for( int i = 0 ; i < vexnum ; i++)
	{
		scanf("%d",&weight[i]) ;
		visited[i] = 0 ;
	}

	for ( int i = 0 ; i < vexnum ; i++ )
	{
		for ( int j = 0 ; j < vexnum ; j++ )
		{
			map[i][j] = map[j][i] = INF_MAX ;
		}
	}

	for( int i = 0 ; i < arcnum ; i++ )
	{
		 scanf("%d%d%d",&from, &to, &w) ;

		 map[from][to]=map[to][from] = w ;
	}
}

void dfs ( int cur, const int target, int curPath , int curWeight )
{
	if ( cur == target )
	{
		if ( curPath < sPath)
		{
			counter = 1 ;
			sPath = curPath ;
			nWei = curWeight ;

		}
		else if ( curPath == sPath )
		{
			counter++ ;

			if ( curWeight > nWei )
			{
				nWei = curWeight ;
			}
		}

		return ;
	}

	if ( curPath > sPath )
		return ;


	for ( int i = 0 ; i < vexnum ;i++ )
	{
		if ( visited[i] == 0 && map[cur][i] != INF_MAX)
		{
			visited[i] = 1 ;
			dfs( i , target,curPath+map[cur][i], curWeight+weight[i] ) ;
			visited[i] = 0 ;
		}
	}

}

int main ( void )
{
	sPath = INF_MAX;

	inPut() ;

	dfs( start , end , 0 , weight[start]) ;

	printf("%d %d",counter , nWei) ;

	return 0 ;

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值