计量地理-最短路径

求解最短路径,输入如下

7 7
0   9  7  2 -1 -1 -1
-1  0 -1 -1  5 -1 -1
-1  5  0  2 -1 -1 -1
-1 -1  4  0 -1  3 -1
-1 -1 -1 -1  0 -1  6
-1  3 -1 -1 11  0  9

-1 -1 -1 -1 -1 -1  0

第一行存储行列数


// ShortestRoute.cpp : Defines the entry point for the console application.
//


#include "stdafx.h"
#include <malloc.h>
#include <stdlib.h>

#include <vector>
using namespace std;

float JudgeMin(float a,float b1,float b2)
{
	if(b2<0)
		return a;
	else
	{
		if(a<0)
			return b1+b2;
		else
		{
			if(a<b1+b2)
				return a;
			else
				return b1+b2;
		}//else
	}	//else
}


void _tmain(int argc, _TCHAR* argv[])
{
	int iNO = 0;		// 循环次数


	int iRow,iCol;	// 矩阵行、列数
	char m_file[] = "图3-10.txt";


	typedef struct LIST{
		float *fM;		// 存储M值
		int iCurPt;		// 当前点


		LIST* pChild;
		LIST* pParent;
	};


	bool* blTransverse;		// 标识点是否已经转变为P标号点
	int iStart,iEnd;			// 最短路径的起点、终点
	bool blExit = false;	// 判断循环是否退出
	float** m_data;				// 存储原始数据矩阵
	int ptCur;						// 当前循环计算的起点点号


	LIST* listH = new LIST;	// 头指针
	LIST* listE;	// 尾指针


	// 读文件
	FILE *fp;


	if((fp = fopen(m_file,"r")) == NULL){
		printf("can not open this file\n");
		return;


	};


	fscanf(fp,"%d %d",&iRow,&iCol);
	//动态定义原始数据
	m_data = (float**)malloc(sizeof(m_data) * iRow);
	for(int i = 0;i < iRow;i++)
		m_data[i] = (float*)malloc(sizeof(m_data) * iCol);


	listH->fM = new float[iRow - 1];
	blTransverse = new bool[iRow - 1];
	for(int i = 0;i < iRow;i++){
		listH->fM[i] = -1.0;
		blTransverse[i] = false;


	}


	int i = 0,j = 0;
	while(!feof(fp)){
		fscanf(fp, "%f", &m_data[i][j]);		
		j++;
		if(j == iCol){
			i++;			j=0;
		}
	}	


	fclose(fp);


	//选择最短路径的起点和终点
	printf("Please input start point(>=1), iStart = ");
	scanf("%d",&iStart);
	printf("\nPlease input end point(<=7), iEnd = ");
	scanf("%d",&iEnd);


	listH->iCurPt = iStart;
	listH->pParent = NULL;
	listH->pChild  = NULL;
	listH->fM[iStart - 1] = 0.0;


	blTransverse[iStart - 1] = true;
	ptCur = iStart;


	LIST* listCur = listH;
	LIST* listChild;


	while(!blExit){
		blExit = true;


		//对每一个点在循环之前,判断是否所有点都变为固定标号
		for(int i = 0;i < iRow;i++){
			if(!blTransverse[i]){
				blExit = false;
				break;


			}
		}


		if(blExit)			continue;
		iNO++;


		// 对于每一个顶点进行循环,计算以当前标记点到其它点之间的距离
		for(int i = 0;i < iRow;i++){
			if(!blTransverse[i]){		// 是否已经被遍历
				float temp = JudgeMin(listCur->fM[i],listCur->fM[ptCur - 1],m_data[ptCur - 1][i]);
				listCur->fM[i] = temp;
				
			}
		}


		// 寻找最小值所对应的点号
		bool blExist = false;			// 下次循环是否存在点
		float temp = 99999999999;
		for(int i = 0;i < iRow;i++){			
			if(!blTransverse[i]){
				if(temp > listCur->fM[i] && listCur->fM[i] > 0){
					temp = listCur->fM[i];
					ptCur = i + 1;					
					blExist = true;


				}
			}			
		}


		// 若存在点,则分配空间;否则,退出循环
		if(blExist){
			listChild = new LIST;	
		}
		else{
			printf("Cannot arrive at some point\n");
			
			break;


		}


		if(listChild){
			listChild->pChild = NULL;
			listChild->fM = new float[iRow - 1];


			for(int i = 0;i < iRow;i++)
				listChild->fM[i] = listCur->fM[i];


			blTransverse[ptCur - 1] = true;
			listChild->iCurPt = ptCur;
			
			listChild->pParent = listCur;
			listCur->pChild = listChild;


			listCur = listCur->pChild;


		}


	}


	// 确定链表的长度
	LIST* pBake = listH;
	int iLength = 0;
	while(listH->pChild != NULL){
		listH = listH->pChild;
		iLength++;


	}	
	listH = pBake;
	listE = listCur;
	
	if(listH->pChild == NULL)		iLength = 1;


	printf("循环次数是:%d;链表长度是:%d\n",iNO,iLength);


	// 开始从后向前确定最短路径
	float** m_dist = new float*[iLength];
	for(int i = 0;i < iLength;i++)
		m_dist[i] = new float[iRow];
	int* ptCurList = new int[iLength];
	
	int m = 0;
	while(listH->pChild != NULL){		
		for(int n = 0;n < iRow;n++){
			m_dist[m][n] = listH->fM[n];


		}


		ptCurList[m] = listH->iCurPt;


		listH = listH->pChild;
		m++;


	}	
	listH = pBake;


	vector <int> ptVect;
	ptVect.push_back(iEnd);
	ptCur = iEnd;
	blExit = false;


	
	// 首先判断终点是否有值,如果没有则表示无法到达
	if(m_dist[iLength - 1][ptCur - 1] < 0){
		printf("Cannot arrive at the end point\n");		
		system("pause");


		return;


	}
	
	for(int i = iLength - 1;i >= 0;i--){
		for(int j = iLength - 2;j >= 0;j--){
			if(m_dist[i][ptCur - 1] < m_dist[j][ptCur - 1] && m_dist[j][ptCur - 1] > 0){
				ptCur = ptCurList[i - 1];		// 这个是关键


				ptVect.push_back(ptCur);


				i = j;
				j = iLength - 2;


			}


			if(m_dist[j][ptCur - 1] < 0){
				ptCur = ptCurList[j + 1];


				ptVect.push_back(ptCur);


			}
		}
	}
	
	ptVect.push_back(iStart);


	// 输出路径
	printf("最短路径是:\n");	
	for(int i = ptVect.size() - 1;i >= 0;i--){
		printf("%d ",ptVect[i]);
		if(i != 0)		printf("-> ");


	}
	
	// 释放链表
	while(listE->pParent != NULL){
		LIST* temp = listE;
		listE = listE->pParent;
		listE->pChild = NULL;


		delete temp;		


	}	
		
	system("pause");
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值