算法导论11--最小生成树电网长度问题

一、目的
1.熟悉算法设计的基本思想
2.掌握最小生成树算法的思路
二、内容与设计思想

国家电网公司想在全国布局超高压输电网络,联通所有省会城市。为了降低成本,并且达到某些硬性要求,国家电网按照以下五种策略进行规划布局。
(1)要求整个电网的长度最短。
(2)要求在西宁与郑州拉一根直达专线的情况下,使得整个电网长度最短
(3)要求不仅在西宁与郑州之间拉直达专线,还在杭州与长沙之间拉直达专线的情况下,使得整个电网长度最短。
(4)在香港与澳门、澳门与广州不拉直达线路的前提之下,使得整个电网的长度最短。
(5)山东、河南、陕西、甘肃、青海、新疆以及比他们更北的省份称为北方省份,其余省份称为南方省份。如果在南方省份和北方省份之间仅规划一条直通专线,如何使得整个电网的长度最短。
请分别根据这五种情况计算最优情况。
提示:

  1. 如无特殊约定,各个城市之间均可拉专线,其长度是直线长度。
  2. 地球上任意两点之间的距离计算方法可以参照以下文件:https://www.cnblogs.com/ycsfwhh/archive/2010/12/20/1911232.html
    摘录如下:
    地球是一个近乎标准的椭球体,它的赤道半径为6378.140千米,极半径为 6356.755千米,平均半径6371.004千米。如果我们假设地球是一个完美的球体,那么它的半径就是地球的平均半径,记为R。如果以0度经线为基 准,那么根据地球表面任意两点的经纬度就可以计算出这两点间的地表距离(这里忽略地球表面地形对计算带来的误差,仅仅是理论上的估算值)。设第一点A的经 纬度为(LonA, LatA),第二点B的经纬度为(LonB, LatB),按照0度经线的基准,东经取经度的正值(Longitude),西经取经度负值(-Longitude),北纬取90-纬度值(90- Latitude),南纬取90+纬度值(90+Latitude),则经过上述处理过后的两点被计为(MLonA, MLatA)和(MLonB, MLatB)。那么根据三角推导,可以得到计算两点距离的如下公式:

C = sin(MLatA)*sin(MLatB)*cos(MLonA-MLonB) + cos(MLatA)cos(MLatB)
Distance = R
Arccos©*Pi/180

这里,R和Distance单位是相同,如果是采用6371.004千米作为半径,那么Distance就是千米为单位,如果要使用其他单位,比如mile,还需要做单位换算,1千米=0.621371192mile
如果仅对经度作正负的处理,而不对纬度作90-Latitude(假设都是北半球,南半球只有澳洲具有应用意义)的处理,那么公式将是:

C = sin(LatA)*sin(LatB) + cos(LatA)*cos(LatB)cos(MLonA-MLonB)
Distance = R
Arccos©*Pi/180

以上通过简单的三角变换就可以推出。

  1. 全国省会城市的经纬度如下所示。
城市,经度,纬度
沈阳市,123.429092,41.796768
长春市,125.324501,43.886841
哈尔滨市,126.642464,45.756966
北京市,116.405289,39.904987
天津市,117.190186,39.125595
呼和浩特市,111.751990,40.841490
银川市,106.232480,38.486440
太原市,112.549248,37.857014
石家庄市,114.502464,38.045475
济南市,117.000923,36.675808
郑州市,113.665413,34.757977
西安市,108.948021,34.263161
武汉市,114.298569,30.584354
南京市,118.76741,32.041546
合肥市,117.283043,31.861191
上海市,121.472641,31.231707
长沙市,112.982277,28.19409
南昌市,115.892151,28.676493
杭州市,120.15358,30.287458
福州市,119.306236,26.075302
广州市,113.28064,23.125177
台北市,121.5200760,25.0307240
海口市,110.199890,20.044220
南宁市,108.320007,22.82402
重庆市,106.504959,29.533155
昆明市,102.71225,25.040609
贵阳市,106.713478,26.578342
成都市,104.065735,30.659462
兰州市,103.834170,36.061380
西宁市,101.777820,36.617290
拉萨市,91.11450,29.644150
乌鲁木齐市,87.616880,43.826630
香港,114.165460,22.275340
澳门,113.549130,22.198750

三、使用环境

推荐使用C/C++集成编译环境。

四、实验过程

1、编写相关实验代码

#include<bits/stdc++.h>
using namespace std;

#define Infinity 65535
#define ERROR -1
#define Pi 3.14
#define R 6371.004

int Index[35];
string Arr[35]={"沈阳","长春","哈尔滨","北京","天津","呼和浩特","银川",
			"太原","石家庄","济南","郑州","西安","武汉","南京","合肥",
			"上海","长沙","南昌","杭州","福州","广州","台北","海口",
			"南宁","重庆","昆明","贵阳","成都","兰州","西宁","拉萨",
			"乌鲁木齐","香港","澳门"};
double S[35][2]={{123.429092,41.796768},
				{125.324501,43.886841},
				{126.642464,45.756966},
				{116.405289,39.904987},
				{117.190186,39.125595},
				{111.751990,40.841490}, 
				{106.232480,38.486440},
				{112.549248,37.857014},
				{114.502464,38.045475}, 
				{117.000923,36.675808},
				{113.665413,34.757977}, 
				{108.948021,34.263161}, 
				{114.298569,30.584354}, 
				{118.76741,32.041546}, 
				{117.283043,31.861191}, 
				{121.472641,31.231707}, 
				{112.982277,28.19409}, 
				{115.892151,28.676493}, 
				{120.15358,30.287458}, 
				{119.306236,26.075302}, 
				{113.28064,23.125177}, 
				{121.5200760,25.0307240},
				{110.199890,20.044220}, 
				{108.320007,22.82402}, 
				{106.504959,29.533155}, 
				{102.71225,25.040609}, 
				{106.713478,26.578342}, 
				{104.065735,30.659462}, 
				{103.834170,36.061380}, 
				{101.777820,36.617290}, 
				{91.11450,29.644150}, 
				{87.616880,43.826630}, 
				{114.165460,22.275340}, 
				{113.549130,22.198750}};

typedef struct GNode
{
	int Nv;
	int Ne;
	double G[1000][1000];
//	int Data[1000];
} MGraph;

typedef struct ENode
{
	int V1,V2;
	double Weight;
} Edge;

MGraph* CreateGraph(int VertexNum)
{
	int V,W;
	MGraph* Graph;
	
	Graph=new MGraph;
	Graph->Nv=VertexNum;
	Graph->Ne=0;
	
	for (V=0;V<Graph->Nv;V++)
	{
		for (W=0;W<Graph->Nv;W++)
		{
			Graph->G[V][W]=Infinity;
		}
	}
	
	return Graph;
}

void InsertEdge(MGraph* Graph,Edge* E)
{
	Graph->G[E->V1][E->V2]=E->Weight;                      
}

MGraph* BuildGraph(MGraph* Graph,double D[])
{
	Edge* E;
	int V;
	int Nv,Ne,i,j,k;
	k=0;

	Nv=34;
	Ne=1156; 
	
	Graph=CreateGraph(Nv);
	Graph->Ne=Ne;
	
	for (V=0;V<Nv;V++)
	{
		Index[V]=V; 
	}
	
	if (Graph->Ne!=0)
	{
		E=new Edge;
		
		for (i=0;i<Nv;i++)
		{
			for (j=0;j<Nv;j++)
			{
				E->V1=Index[i];
				E->V2=Index[j];
				E->Weight=D[k];
				InsertEdge(Graph,E);
				k++;
			}
		}
		
	}
	
	return Graph;
}

int FindMin(MGraph* Graph,double dist[])
{
	int MinV,V;
	double MinDist=Infinity;
	
	for (V=0;V<Graph->Nv;V++)
	{
		if (dist[V]!=0&&dist[V]<MinDist)
		{
			MinDist=dist[V];
			MinV=V;
		}
	}
	
	if (MinDist<Infinity)
	{
		return MinV;
	}
	else
	{
		return ERROR;
	}
}

void Print(double a[],int b[],int c[],int k,MGraph* Graph)
{
	int i,j,t;
	
	for (i=0;i<k;i++)
	{
		cout<<Arr[b[i]]<<"--"<<Arr[c[i]]<<":"<<a[i]<<endl;
	} 
}

double Prim(MGraph* Graph,MGraph* MST)
{
	int k=0;
	double a[10000];
	int b[10000],c[10000];
	double dist[10000],TotalWeight;
	int parent[10000],V,W;
	int VCount;
	Edge* E;
	
	for (V=0;V<Graph->Nv;V++)
	{
		dist[V]=Graph->G[0][V];
		parent[V]=0;
	}
	TotalWeight=0;
	VCount=0;
	
	MST=CreateGraph(Graph->Nv);
	E=new Edge;
	
	dist[0]=0;
	VCount++;
	parent[0]=-1;
	
	while(1)
	{
		V=FindMin(Graph,dist);
		if (V==ERROR)
		{
			break;
		}
		E->V1=parent[V];
		E->V2=V;
		E->Weight=dist[V];
		InsertEdge(MST,E);
		TotalWeight+=dist[V];
		dist[V]=0;
		VCount++;
		
		a[k]=E->Weight;
		b[k]=E->V1;
		c[k]=E->V2;
		k++;
		
		for (W=0;W<Graph->Nv;W++)
		{
			if (dist[W]!=0&&Graph->G[V][W]<Infinity)
			{
				if (Graph->G[V][W]<dist[W])
				{
					dist[W]=Graph->G[V][W];
					parent[W]=V;
				}
			}
		}
	}
	
	if (VCount<Graph->Nv)
	{
		TotalWeight=ERROR;
	}
	
	Print(a,b,c,k,Graph);
	
	return TotalWeight;
}

int main()
{
	MGraph* Graph;
	MGraph* MST;
	double Total;
	int i,j,k;
	double D[10000];
	double C;
	
	k=0;
	for (i=0;i<34;i++)
	{
		for (j=0;j<34;j++)
		{
			C=sin(S[i][1]*Pi/180)*sin(S[j][1]*Pi/180)+cos(S[i][1]*Pi/180)*cos(S[j][1]*Pi/180)*cos(S[i][0]*Pi/180-S[j][0]*Pi/180);
			D[k]=R*acos(C);
			k++;
		}
	}
	
	Graph=BuildGraph(Graph,D);
	Total=Prim(Graph,MST);
	
	cout<<Total;
	
	return 0;
}

2、写出算法的思路。
(2)第二题西宁和郑州拉线,就先让这两个城市之间连一条线,然后从郑州开始使用最小生成树;
(3)在第二题的基础上,设置一个flag=0,遇到杭州或者长沙时,flag+1,当flag=1时,跳过循环直接使杭州与长沙相连,之后再回到循环;
(4)在第一题的基础上,如果两端点是港澳或者广州澳门,那么把它的dist[V]设置为无穷,再利用FindMin函数,其余不变。
(5)把南北城市分开,分别使用Prim算法,再从南北城市之间的距离找到最小值,三者结合即为解。
3、输出各组实验的电网数据表,以及电网总长度,并且通过可视化方式进行呈现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值