La décima pregunta de la 11.ª competencia provincial de simulación de la Copa Lanqiao C++ (algoritmo prim)

Descripción del problema

En 2015, todos los hogares de China recibieron electricidad. Como generador de energía, Xiao Ming está ayudando a los países a lo largo de la Franja y la Ruta a obtener electricidad.
  Esta vez, Xiao Ming quiere ayudar a n aldeas a obtener electricidad, y la aldea número 1 puede simplemente construir una central eléctrica y la electricidad generada es suficiente para todas las aldeas.
  Ahora, no hay cables que conecten estas aldeas N. Lo que Xiaoming debe hacer principalmente es conectar estas aldeas con cables, de modo que todas las aldeas estén conectadas directa o indirectamente a la central eléctrica.
  Xiao Ming ha medido las posiciones (coordenadas) y las alturas de todas las aldeas. Si quiere conectar dos aldeas, Xiao Ming necesita gastar la distancia coordinada entre las dos aldeas más el cuadrado de la diferencia de altura. La descripción formal es que las coordenadas son (x_1, y_1) altura El costo de conectar un pueblo en h_1 a un pueblo en la altura h_2 en las coordenadas (x_2, y_2) es
  sqrt((x_1-x_2)(x_1-x_2)+(y_1-y_2)(y_1- y_2))+(h_1 -h_2)*(h_1-h_2).
  En la fórmula anterior, sqrt significa sacar la raíz cuadrada entre paréntesis. Preste atención a la posición de los corchetes, el método de cálculo de la altura es diferente del método de cálculo de las coordenadas horizontales y verticales.
  Debido a los fondos limitados, ayude a Xiao Ming a calcular cuánto necesita gastar al menos para electrificar las n aldeas.

formato de entrada

La primera línea de entrada contiene un número entero n que indica el número de aldeas.
  En las próximas n líneas, cada tres números enteros x, y, h representan la abscisa, y y la altura de un pueblo, y el primer pueblo puede construir una central eléctrica.

formato de salida

Muestra una línea que contiene un número real redondeado a 2 decimales para indicar la respuesta.

entrada de muestra

4
1 1 3
9 9 7
8 8 6
4 5 4

salida de muestra

17.41

Acuerdo y escala de casos de uso de evaluación

Para el 30% de los casos de evaluación, 1 <= n <= 10;
  para el 60% de los casos de evaluación, 1 <= n <= 100;
  para todos los casos de evaluación, 1 <= n <= 1000, 0 <= x, y, h <= 10000.
  
Idea de respuesta: este es un problema clásico de árbol de expansión mínimo. La prueba de datos aquí es hasta 1000, por lo que podemos usar la matriz de adyacencia para almacenar este gráfico. Si hay más de 1000, podemos usar la lista de adyacencia para hacerlo;

#include<iostream> 
#include<math.h>
#include<stdio.h>
using namespace std;
const int Max=1000;//最多1000个节点;
double  jz[Max][Max];//构造邻接矩阵;
const double inf=9999.9;
int n;//有多少个村庄 
int vis[Max]={
    
    0};//用来判断这个节点是否被访问了,初始化为0 
double d[Max]; //d[i]代表着第i个节点到这个s集合里面的最短距离 
void init()//初始化领接矩阵 
{
    
    
	for(int i=0;i<n;i++)
	{
    
    
		for(int j=0;j<n;j++)
		{
    
    
			jz[i][j]=inf;
		}
	}
}
void init1()//初始化d[Max]; 
{
    
    
	for(int i=0;i<n;i++)
	{
    
    
		d[i]=inf;
	}
}
double prim()//prim算法 
{
    
        
	
    double ans=0; 
	init1();//这里注意一定先初始化d[Max],在对第一个赋值 
    d[0]=0;
    for(int i=0;i<n;i++)
    {
    
    
    	int u=-1;
		double min=inf;
    	for(int j=0;j<n;j++)
    	{
    
        
    	    if(vis[j]==0&&d[j]<min)//将当前可以访问到s集合里面的顶点,并且是距离最短的加入到s集合中 
			{
    
    
			
				u=j;
				min=d[j];	
			}	  
    	}
    	if(u==-1)
    	{
    
    
    		return -1;
    	}
    	ans+=d[u];
    	vis[u]=1;//将节点设置为访问过了 
    	for(int v=0;v<n;v++)
    	{
    
         
    		if(vis[v]==0&&jz[u][v]!=inf&&jz[u][v]<d[v])//与当前没有访问过的节点&&可以访问到u节点&&到这个u的距离比到s集合的最短距离要小 
    		{
    
    	
    			d[v]=jz[u][v];
    		}
    			
    	}	
    }
	return ans;	
} 
double js(int x1,int y1,int h1,int x2,int y2,int h2)
{
    
    
	double w= sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))+(h1-h2)*(h1-h2);	
	return w;
}
int main()
{
    
    
    cout<<"请输入村庄的数量:";
	cin>>n;
	int num[n][3];
	init();
	cout<<"请输入每个村子的X,Y,H:"<<endl;
	for(int i=0;i<n;i++)
	{
    
    	
		cin>>num[i][0]>>num[i][1]>>num[i][2]; 	
	}
    for(int i=0;i<n;i++)
    {
    
    
    	for(int j=0;j<n;j++)
    	{
    
    	
    		if(i!=j)
    		{
    
    
    			double w;//两个之间建立电路的金额 
    			w=js(num[i][0],num[i][1],num[i][2],num[j][0],num[j][1],num[j][2]);
    			jz[i][j]=w;		
    		}
    	}
    } 
	printf("%.2lf",prim());
	return 0;
}

Resumen: utilizo el algoritmo prim más tradicional para resolver el problema. Básicamente, aplico el algoritmo prim del libro. Para este problema, presto atención principalmente a los tipos de datos que contiene.

Supongo que te gusta

Origin blog.csdn.net/qq_44741914/article/details/105624834
Recomendado
Clasificación