1. 程式人生 > >狄克斯特拉演算法求解村莊問題

狄克斯特拉演算法求解村莊問題

問題:

給定n個村莊之間的交通圖。若村莊ij之間有路可通,則ij用邊連線,邊上的權值Wij表示這條道路的長度。現打算在這n個村莊中選定一個村莊建一所醫院。編寫如下演算法:

(1) 求出該醫院應建在哪個村莊,才能使距離醫院最遠的村莊到醫院的路程最短。

(2) 求出該醫院應建在哪個村莊,能使其它所有村莊到醫院的路徑總和最短。


完成專案程式碼如下:

resource.h標頭檔案

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Resource.rc

// 新物件的下一組預設值
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        101
#define _APS_NEXT_COMMAND_VALUE         40001
#define _APS_NEXT_CONTROL_VALUE         1001
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

targetver.h標頭檔案

#pragma once

// 包括 SDKDDKVer.h 將定義可用的最高版本的 Windows 平臺。

// 如果要為以前的 Windows 平臺生成應用程式,請包括 WinSDKVer.h,並將
// WIN32_WINNT 巨集設定為要支援的平臺,然後再包括 SDKDDKVer.h。

#include <SDKDDKVer.h>

stdafx.h標頭檔案

// stdafx.h : 標準系統包含檔案的包含檔案,
// 或是經常使用但不常更改的
// 特定於專案的包含檔案
//

#pragma once

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>



// TODO:  在此處引用程式需要的其他標頭檔案
#include<iostream>
#include<fstream>
#include<sstream>
#include<string>
using namespace std;

const int MAX_N = 100;//定義最大儲存空間
const int INF = 65535;//定義為無窮大

//資料節點
//頂點資訊
class Vertex
{
public:
	int vername;//頂點名
	int number;//頂點下標
};

//圖資訊
class MatrixGraph
{
public:
	int edges[MAX_N][MAX_N];//邊
	int Tvertex, Tedges;//總頂點,總邊數
	Vertex vert[MAX_N];//頂點資訊
	int weight[MAX_N];//邊權重
};

class Graph
{
public:

	//構造
	Graph();
	//析構
	~Graph();
	//讀取檔案->圖資訊
	void getInfo(string );
	//建立圖
	void CreateGraphMatrix();
	//求任意二者間最短距離
	void solveMin();
	//求解問題
	void solveQuestion();
	
private:
	MatrixGraph graph;
	string vertex;//頂點
	string weight;//權重
	string edges[MAX_N];//邊
	int Tedges;//邊數
	stringstream sstr;//string型別轉換變數
	int disMin[MAX_N][MAX_N];//最短距離

	//獲取下標
	int location(MatrixGraph , int );
	//初始化鄰接矩陣
	void InitMatrix();
	//初始化距離陣列和路徑陣列
	void InitDist();
	
};

stdafx.cpp檔案
// stdafx.cpp : 只包括標準包含檔案的原始檔
// solveGraphQuestion.pch 將作為預編譯頭
// stdafx.obj 將包含預編譯型別資訊

#include "stdafx.h"

// TODO:  在 STDAFX.H 中
// 引用任何所需的附加標頭檔案,而不是在此檔案中引用


//構造
Graph::Graph()
{
	Graph::InitMatrix();//初始化矩陣
	Graph::InitDist();//初始化距離
}

//析構
Graph::~Graph(){}

//搜尋下標
int Graph::location(MatrixGraph g, int index)
{
	for (int i = 0; i < g.Tvertex; i++)
	{
		if (index == g.vert[i].number)
		{
			return i;
		}
	}
	return -1;
}

//鄰接矩陣初始化
void Graph::InitMatrix()
{
	{
		for (int i = 0; i < MAX_N; i++)
		{
			for (int j = 0; j < MAX_N; j++)
			{
				graph.edges[i][j] = INF;//初始化為無窮大
			}
		}
	}
}

//村莊間距離初始化
void Graph::InitDist()
{
	for (int i = 0; i < MAX_N; i++)
	{
		for (int j = 0; j < MAX_N; j++)
		{
			disMin[i][j] = INF;//初始化為無窮大
		}
	}
}

//讀取檔案->圖資訊
void Graph::getInfo(string filename)
{
	ifstream readfile;
	readfile.open(filename, ios::in);
	getline(readfile, vertex);//讀取頂點
	getline(readfile, weight);//讀取權重
	//讀取邊
	int i = 0;
	while (!readfile.eof())
	{
		if (getline(readfile, edges[i]).good())//邊值正常
		{
			i++;
		}
	}
	readfile.close();
	Tedges = i;//總邊數
}

//建立圖
void Graph::CreateGraphMatrix()
{
	int edge1, edge2;
	graph.Tvertex = vertex.length();//頂點數
	graph.Tedges = Tedges;//邊數

	//處理頂點
	for (int i = 0; i < graph.Tvertex; i++)
	{
		//轉換
		sstr.clear();//清空記憶體
		sstr << vertex[i];//寫入一個頂點
		sstr >> graph.vert[i].vername;//獲取一個頂點
		graph.vert[i].number = i;//定義頂點編號
	}

	//處理邊
	for (int i = 0; i < graph.Tedges; i++)
	{
		//轉換
		sstr.clear();//清空記憶體
		sstr << weight[i];//寫入權重
		sstr >> graph.weight[i];//獲取權重
		sstr.clear();
		sstr << edges[i][0];//獲取一條邊始點
		sstr >> edge1;
		sstr.clear();
		sstr << edges[i][1];//獲取一條邊終點
		sstr >> edge2;
		int p1 = location(graph, edge1);//獲取始點邊下標
		int p2 = location(graph, edge2);//獲取終點邊下標
		graph.edges[p1][p2] = graph.edges[p2][p1] = graph.weight[i];//寫入該邊權重->無向
	}
}

//求任意村莊間最短距離
void Graph::solveMin()
{
	//預設最短距離
	for (int i = 0; i < graph.Tvertex; i++)
	{
		for (int j = 0; j < graph.Tvertex; j++)
		{
			disMin[i][j] = graph.edges[i][j];
		}
	}

	//求最短距離
	for (int k = 0; k < graph.Tvertex; k++)
	{
		for (int i = 0; i < graph.Tvertex; i++)
		{
			for (int j = 0; j < graph.Tvertex; j++)
			{
				if (disMin[i][j]>disMin[i][k] + disMin[k][j])
				{
					disMin[i][j] = disMin[i][k] + disMin[k][j];//修改最短距離
				}
			}
		}
	}
}

//求解問題
void Graph::solveQuestion()
{
	int min[MAX_N];//某村莊到其他村莊的最短距離中的最大距離
	int totalMin[MAX_N] = { 0 };//某村莊到其他村莊的最短距離之和

	//遍歷求村莊到其他村莊的最短距離中的最大距離
	//以及到其他村莊的最短距離之和
	for (int i = 0; i < graph.Tvertex; i++)
	{
		min[i] = disMin[i][0];//預設距離最大
		for (int j = 0; j<graph.Tvertex; j++)
		{
			//若存在更大值,則更新
			if (min[i] < disMin[i][j])
			{
				min[i] = disMin[i][j];//修改最大值
			}

			totalMin[i] += disMin[i][j];//距離之和
		}
	}

	//求解問題
	int ques_1 = min[0], loc_1 = 0;//問題一最小值以及村莊下標
	int ques_2 = totalMin[0], loc_2 = 0;//問題二最小值以及村莊下標
	
	for (int i = 0; i < graph.Tvertex; i++)
	{
		//存在更小距離
		if (ques_1>min[i])
		{
			ques_1 = min[i];//修改距離
			loc_1 = i;//修改村莊下標
		}
		//存在更小距離之和
		if (ques_2 > totalMin[i])
		{
			ques_2 = totalMin[i];//修改距離
			loc_2 = i;//修改下標
		}
	}

	//輸出結果
	cout << "question 1->村莊標號 " << loc_1 << ", 最短距離 " << ques_1 << endl;
	cout << "question 2->村莊標號 " << loc_2 << ", 最短距離 " << ques_2 << endl;
}

solveGraphQuestion.cpp檔案
// solveGraphQuestion.cpp : 定義控制檯應用程式的入口點。
//
//程式碼所解決問題說明見readMe.txt

#include "stdafx.h"


int _tmain(int argc, _TCHAR* argv[])
{
	Graph g;
	g.getInfo("data.txt");//讀圖
	g.CreateGraphMatrix();//建立臨接矩陣
	g.solveMin();//求所有最短路徑
	g.solveQuestion();//求解問題
	return 0;
}

data.txt檔案資訊

012345
5873459561
01
02
03
05
12
23
25
34
35
45


執行結果: