PAT程序设计练习——甲级1003(任意两个城市最短距离、Floyd最短路径算法)

题目原文链接:点击打开链接

翻译题目要求:

程序的输入:第一行包含4个整数,用空格分开,分别代表城市的数量N、道路的数量M、当前出发的城市序号C1、目的地城市序号C2;第二行需要输入N个整数,用空格分开,顺序代表每个城市拥有的救援人员数量;接下来需要输入M行,每行包括3个整数描述道路信息,分别是 道路起点序号、道路另一起点序号、道路长度,用空格分隔。

程序的输出:计算出C1到C2之间最短距离的数目、可以得到救援人员的最大数量(单个道路内)。

设计思路如下:

通过输入创建图矩阵后,使用Floyd算法算出最短路径的同时,使用辅助数组记录每对两点之间存在相同距离的case,最后通过Floyd的path数组和辅助数组,计算出C1到C2的距离和途径。

代码如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <vector>

using namespace std;

#define	MatrixSize	100
#define INFINITE	65535

typedef int	WeightType;
typedef int	VertexType;
typedef struct tagGraph 
{
	VertexType point[MatrixSize];				//顶点value数组
	WeightType matrix[MatrixSize][MatrixSize];	//路径权重矩阵表
	int vertexNumber;							//顶点数量
	int edgeNumber;								//路径数量
}Graph,*pGraph;

typedef struct tagFindSamePath 
{
	tagFindSamePath()
	{
		findHead = -1;
		findEnd = -1;
		findMid = -1;
		findListIndex = 0;
	}
	void Reset()
	{
		findHead = -1;
		findEnd = -1;
		findMid = -1;
	}
	int findHead;					//在已有队列中发现多路的起始点序号
	int findEnd;					//在已有队列中发现多路的终点序号
	int findMid;					//新的起始点和终点的第一个后继点实值,插入到新的队列中
	int findListIndex;				//目标已有队列序号
}SamePath,*pSamePath;

typedef struct tagPathList
{
	tagPathList()
	{
		size = 0;
		list = NULL;
		distance = NULL;
	}
	int**	list;
	int		size;
	int*	distance;
}PathList,*pPathList;

int*			path = NULL;
int*			distanceMatrix = NULL;
int*			samePath = NULL;

Graph						graph;
PathList					avalPath;
vector<SamePath>	SamePathRecord;

int CreateGraph( Graph* p)
{
	int v1,v2,distance;

	for ( int i = 0; i < p->vertexNumber; i++ )
	{
		for ( int j = 0; j < p->vertexNumber; j++ )
		{
			if ( i == j )	p->matrix[i][j] = 0;
			else			p->matrix[i][j] = INFINITE;
		}
	}
	for ( int i = 0; i < p->edgeNumber; i++ )
	{
		printf("Please Input the pair of two cities and their Distance:\n");
		getchar();
		scanf("%d %d %d", &v1, &v2, &distance );

		p->matrix[v1][v2] = distance;
		p->matrix[v2][v1] = distance;
	}
	return 0;
}

int PrintMatrixResult( Graph* p )
{
	for ( int i = 0; i < p->vertexNumber; i++ )
	{
		for ( int j = 0; j < p->vertexNumber; j++ )
		{
			printf( "%d ",p->matrix[i][j] );
		}
		printf("\n");
	}
	return 0;
}
void ParseValueOfPoint( Graph* graph, char* buf )
{
	int index = 0;
	char buffer[200] = {0};
	strcpy( buffer, buf );
	char* p = buffer;

	p = strtok( buffer, " " );
	while ( p != NULL )
	{
		graph->point[index++] = atoi( p );
		p = strtok( NULL, " " );
	}
}
void Floyd( Graph* graph )
{
	int size = graph->vertexNumber;
	int used = 0;

	path = (int*)malloc( size*size*sizeof(int) + 1 );
	distanceMatrix = (int*)malloc( size*size*sizeof(int) + 1 ); 
	samePath = (int*)malloc( 3*size*sizeof(int) );

	for( int i = 0; i < size; i++ )
		for( int j = 0; j < size; j++ )
		{
			*(distanceMatrix+ i*size + j) = graph->matrix[i][j];
			*(path + i*size + j) = j;
		}
		for( int k = 0; k < size; k++ )
			for( int i = 0; i < size; i++ )
				for( int j = 0; j < size; j++ )
				{
					if ( i == j || ( i == k || j == k ) )
					{
						continue;
					}
					int c = *( distanceMatrix + i*size + j );
					int c1 = *( distanceMatrix + i*size + k );
					int c2 = *( distanceMatrix + k*size + j );
					if( c1 > 0 && c1 < INFINITE 
						&& c2 > 0 && c2 < INFINITE
						&& c >= c1 + c2 )
					{
						if( c == c1 + c2 )
						{
							samePath[used++] = i; 
							samePath[used++] = j; 
							samePath[used++] = k;
						}
						else
						{
							*(distanceMatrix + i*size + j) = c1 + c2;
							*(path + i*size + j ) = *(path + i*size + k);
						}
					}
				}
				samePath[used] = INFINITE;
}
// 在指定的一段缓冲区数组里查找 目标value的位置序号
int findValueFromArray( int* array, int value )
{
	int bFind = -1;
	for ( int i = 0; ; i++ )
	{
		if ( array[i] == INFINITE )
		{
			break;
		}
		if ( array[i] == value )
		{
			bFind = i;
			break;
		}
	}
	return bFind;
}
// 寻找现在发现的新路是否和以前的情况一致
int findConflictSamePath( int head, int end, int mid, int listIndex )
{
	int size = SamePathRecord.size();
	for ( int iLoop = 0; iLoop < size; iLoop++ )
	{
		SamePath path = SamePathRecord[iLoop];
		if ( head == path.findHead && end == path.findEnd && mid == path.findMid && listIndex == path.findListIndex )
		{
			return true;
		}
	}
	return false;
}
// 在已有的路径中根据same表 寻找新路
int FindSamePath( SamePath& path )
{
	for ( int i = path.findListIndex; i < avalPath.size; i++ )
	{
		int* tempList = avalPath.list[i];
		for ( int j = 0; ; j++ )
		{
			if ( tempList[j] == INFINITE )
			{
				break;
			}
			for ( int k = 0; ; k += 3 )
			{
				if ( samePath[k] == INFINITE )
				{
					break;
				}
				if ( tempList[j] == samePath[k] )
				{
					path.findEnd = findValueFromArray( tempList+(j+1), samePath[k+1] );
					path.findMid = findValueFromArray( tempList + (j+1), samePath[k+2] );
					if ( path.findEnd != -1 && path.findMid == -1 )
					{
						path.findHead = j;						//记录目标队列里的i
						path.findEnd = j+1+path.findEnd;		//记录目标队列里的j
						path.findMid = samePath[k+2];			//记录same表中的k
						path.findListIndex = i;					//记录目标队列所在的序号

						// 和以前匹配的记录要不一致才可以视为新路
						if ( findConflictSamePath( path.findHead, path.findEnd, path.findMid, path.findListIndex ) == false ) 
						{
							SamePathRecord.push_back( path );
							return true;
						}
						else continue;
					}
					else
					{
						continue;
					}
				}
			}
		}
	}
	return false;
}
// 发现新路径后,依据FindSamePath结构体 在路径数组里面追加上来
int AppendNewPath( Graph* graph, SamePath path )
{
	int size = graph->vertexNumber;
	int* AimList = avalPath.list[path.findListIndex];
	int* tempList = (int*)malloc( size*sizeof(int) );

	int used = 0;
	for ( int i = 0; ; i++ )
	{
		if ( AimList[i] == INFINITE )
		{
			break;
		}
		if ( i != path.findHead )
		{
			tempList[used++] = AimList[i];
		}
		else if ( i == path.findHead )
		{
			tempList[used++] = AimList[path.findHead];
			tempList[used++] = path.findMid;
			tempList[used++] = AimList[path.findEnd];
			i = path.findEnd;
		}
	}
	tempList[used] = INFINITE;
	avalPath.list[avalPath.size++] = tempList;
	return true;
}

int CalcMaxNumber()
{
	int size = graph.vertexNumber;
	int maxNumber = 0;

	avalPath.distance = (int*)malloc( size*sizeof(int) );

	for ( int i = 0; i < avalPath.size; i++ )
	{
		int* temp = avalPath.list[i];
		int sum = 0;
		for ( int j = 0; ; j++ )
		{
			if ( temp[j] == INFINITE )
			{
				break;
			}
			if ( temp[j] != INFINITE )
			{
				sum += graph.point[temp[j]];
			}
		}
		avalPath.distance[i] = sum;
	}
	avalPath.distance[avalPath.size] = INFINITE;
	// 计算出最大的
	for ( int k = 0; k < avalPath.size; k++ )
	{
		if ( maxNumber < avalPath.distance[k] )
		{
			maxNumber = avalPath.distance[k];
		}
	}
	return maxNumber;
}
// 算出所有可到达、符合条件的路径
void CollectPath( Graph* graph, int current, int dest )
{
	int size = graph->vertexNumber;
	int temp = current;
	int* vertexList = (int*)malloc( size*sizeof(int) );
	int used = 0;
	while ( temp != dest )
	{
		printf( "%d City has value:%d\n",temp,graph->point[temp] );
		vertexList[used++] = temp;

		temp = *( path + temp*size + dest );
	}
	vertexList[used++] = dest;
	vertexList[used] = INFINITE;

	avalPath.list = (int**)malloc( size*sizeof(int*) );
	avalPath.list[avalPath.size++] = vertexList;


	SamePath samePath;
	int result = FindSamePath(samePath);
	while( result )
	{
		AppendNewPath(graph,samePath);
		//新路径追加完毕后继续探索,如有,循环继续追加
		samePath.Reset();
		result = FindSamePath(samePath);
	}
	printf( "the path length is %d and has %d emergency\n", *( distanceMatrix + current*size + dest ), CalcMaxNumber() );

	for ( int i = 0; i < avalPath.size; i++ )
	{
		free(avalPath.list[i]);
	}
}
int main()
{
	int		currentCity = 0;
	int		destCity = 0;
	char	buffer[200] = {0};

	printf("Please Input the Number of Cityies/the Number of path/\nyour Current City/your Destination:\n");
	scanf("%d %d %d %d", &graph.vertexNumber, &graph.edgeNumber, ¤tCity, &destCity );

	printf("Please Input the Number of Emergency Rescue in Every City:\n");
	getchar();
	scanf("%[^\n]",buffer);
	ParseValueOfPoint( &graph, buffer );

	CreateGraph(&graph);

	PrintMatrixResult(&graph);

	Floyd(&graph);

	CollectPath( &graph, currentCity, destCity );

	free(path);
	free(distanceMatrix);
	free(samePath);
	printf("\n");
	return 0;
}

算法还有很大优化的余地,。。。写的过程很是捉急,智商用光了。






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值