Teoría de grafos --- aplicación simple del árbol de expansión mínima

El árbol de expansión mínimo es un punto de conocimiento común en la teoría de grafos. Consiste en encontrar un bloque conectado mínimo en un gráfico para minimizar la suma de pesos. Los algoritmos de cálculo incluyen principalmente los algoritmos Prim y Kruskal. Ambos algoritmos tienen sus propias ventajas y desventajas. Puede consultar mi blog anterior: Graph Theory---Minimum Spanning Tree, Shortest Path_czc131's Blog-CSDN Blog_Minimum Spanning Tree Shortest Path , lo siguiente habla principalmente de varias aplicaciones específicas.

Tabla de contenido

P2872 [USACO07DEC]Construcción de carreteras S 

P1991 Red de comunicación inalámbrica 

P4047 [JSOI2010] División tribal


P2872 [USACO07DEC]Construcción de carreteras S 

Enlace al tema: [USACO07DEC]Construcción de carreteras S - Luogu 

Esta pregunta necesita encontrar el valor mínimo del lado que debe agregarse, porque solo se debe calcular el lado agregado, luego el lado existente es realmente el mismo al calcular, porque no está incluido en el resultado final, por lo que es equivalente a 0, así que cambie la distancia al borde existente a 0 y luego construya el árbol de expansión mínimo en este momento.

Esta pregunta da la información de las coordenadas del punto. Para la comodidad de uso, preprocesé la distancia entre los puntos y la almacené en una matriz.

#include<stdio.h>
#include<algorithm>
#include<math.h>
using namespace std;
#define Inf 0x3f3f3f3f
#define N 1005
#define M 1005
double dis[N][N];
double ssize[N]; //这个点到当前生成树的最短距离
bool vis[N];
int n, m;
struct Node 
{
	int x, y;
}node[M];

double cal_dis(int x, int y)
{
	return sqrt(pow(node[x].x - node[y].x, 2) + pow(node[x].y - node[y].y, 2));
}

double prim(int st)//计算最小生成树权值
{
	vis[st] = 1;
	for (int i = 1; i <= n; i++)
		ssize[i] = dis[st][i];
	double ans = 0;
	while (1)
	{
		int k = -1;
		double Min = Inf;
		for (int i = 1; i <= n; i++)
			if (!vis[i] && ssize[i] <= Min)
			{
				k = i;
				Min = ssize[i];
			}
		if (k == -1)break;
		ans += Min;
		vis[k] = 1;
		for (int i = 1; i <= n; i++)
			if (!vis[i] && ssize[i] > dis[i][k])
				ssize[i] = dis[i][k];//更新到树的最短距离
	}
	return ans;
}

int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++)
		scanf("%d%d", &node[i].x, &node[i].y);
	for(int i=1;i<=n;i++)//计算每个点之间的距离
		for (int j = 1; j <= n; j++)
		{
			dis[i][j] = cal_dis(i, j);
			dis[j][i] = dis[i][j];
		}
	int x, y;
	for (int i = 1; i <= m; i++)
	{
		scanf("%d%d", &x, &y);
		dis[x][y] = 0;
		dis[y][x] = 0;
	}
	printf("%.2lf", prim(1));
	return 0;
}

P1991 Red de comunicación inalámbrica 

Enlace temático: Red de comunicación inalámbrica - Luogu 

Esta pregunta necesita calcular la distancia mínima de transmisión del transceptor requerida para conectar todas las torres centinela. En primer lugar, la torre de vigilancia se considera como un punto. La existencia del teléfono satelital equivale a hacer que la distancia entre dos puntos sea 0 y encontrar el valor mínimo del valor máximo del árbol de expansión . Cuando no hay teléfono satelital, en este momento se convierte en el árbol de expansión mínimo y la distancia de transmisión mínima es el valor máximo en el árbol de expansión en este momento, porque es necesario asegurarse de que las dos torres más lejanas también puedan ser contactadas; la la situación es un poco más complicada con los teléfonos satelitales, un teléfono satelital es inútil, se pueden conectar dos teléfonos satelitales en el lado más grande del árbol de expansión, entonces la respuesta en este momento es el segundo lado más largo, y cada teléfono adicional después de eso, asumiendo que el lado más largo se elimina después del teléfono, el segundo lado más largo El lado es el lado más largo en la actualidad, por lo que hay un teléfono más, siempre puedo conectar el teléfono a cualquier punto en el segundo lado más largo, entonces este punto también entra el bloque conectado y el segundo lado más largo se pueden eliminar, y lo mismo es cierto para continuar agregando teléfonos... Entonces, la respuesta final es ordenar los bordes primero. Si hay llamadas p, se pueden eliminar los bordes largos p-1 , y se puede generar la longitud del borde p-ésimo.

#include<stdio.h>
#include<algorithm>
#include<math.h>
using namespace std;
#define N 600
#define Inf 0x3f3f3f3f
double f[N][N];
double dis[N];
int s,n; //卫星电话的个数和哨所的个数
bool vis[N];
struct Node
{
	int x, y;
}node[N];

double cal_dis(int x, int y)
{
	return sqrt(pow(node[x].x - node[y].x, 2) + pow(node[x].y - node[y].y, 2));
}

int cmp(double x, double y)
{
	return x > y;
}

double Min_dis(int st)
{
	for (int i = 1; i <= n; i++)
		dis[i] = f[st][i];
	vis[st] = 1;
	int num = 0;//答案序列长度
	double ans[N];//答案序列
	while (1)
	{
		int k = -1;
		double Min = Inf;
		for (int i = 1; i <= n; i++)
			if (!vis[i] && dis[i] < Min)
			{
				k = i;
				Min = dis[i];
			}
		if (k == -1)break;
		printf("%d %.2lf\n", k, Min);
		vis[k] = 1;
		ans[++num] = Min;
		for (int i = 1; i <= n; i++)
			if (!vis[i] && f[i][k] < dis[i])
				dis[i] = f[i][k];
	}
	sort(ans + 1, ans + num + 1,cmp);
	for (int i = 1; i <= num; i++)
		printf("%.2lf ", ans[i]);
	printf("\n");
	ans[0] = ans[1];
	return ans[s];
}

int main()
{
	scanf("%d%d", &s, &n);
	for (int i = 1; i <= n; i++)
		scanf("%d%d", &node[i].x, &node[i].y);
	for(int i=1;i<=n;i++)
		for (int j = 1; j <= n; j++)
		{
			f[i][j] = cal_dis(i,j);
			f[j][i] = f[i][j];
		}
	printf("%.2lf", Min_dis(1));
	return 0;
}

P4047 [JSOI2010] División tribal

Enlace temático: Red de comunicación inalámbrica - Luogu [JSOI2010] División tribal - Luogu

Esta pregunta requiere el valor máximo del valor mínimo del árbol de expansión, que se divide en k bloques conectados, y el árbol de expansión mínimo se puede calcular primero. En este momento, es un bloque conectado. Para convertirse en k, entonces Los bordes k-1 deben cortarse como tribus K, porque la distancia debe ser lo más grande posible, luego ordene primero los bordes del árbol de expansión y corte el borde k-1 más largo , y el borde k-1 es la distancia requerida.

#include<algorithm>
#include<math.h>
#include<stdio.h>
using namespace std;
#define Inf 0x3f3f3f3f
#define N 1005
double ans[N];
bool vis[N];
double f[N][N];
double dis[N];
int n, k;
struct Node
{
	int x, y;
}node[N];

double cal_dis(int x, int y)
{
	return sqrt(pow(node[x].x - node[y].x, 2) + pow(node[x].y - node[y].y, 2));
}

int cmp(double x, double y)
{
	return x > y;
}

double find_ans(int st)
{
	for (int i = 1; i <= n; i++)
		dis[i] = f[i][st];
	vis[st] = 1;
	int num = 0;
	while (1)
	{
		int k = -1;
		double Min = Inf;
		for(int i=1;i<=n;i++)
			if (!vis[i] && dis[i] < Min)
			{
				Min = dis[i];
				k = i;
			}
		if (k == -1)break;
		ans[++num] = Min;
		vis[k] = 1;
		//printf("%d %2.lf\n", k, Min);
		for (int i = 1; i <= n; i++)
			if (!vis[i] && dis[i] > f[i][k])
				dis[i] = f[i][k];
	}
	sort(ans + 1, ans + num + 1, cmp);
	return ans[k-1];
}

int main()
{
	scanf("%d%d", &n, &k);
	for (int i = 1; i <= n; i++)
		scanf("%d%d", &node[i].x, &node[i].y);
	for (int i = 1; i <= n; i++)
		for (int j = i; j <= n; j++)
		{
			f[i][j] = cal_dis(i, j);
			f[j][i] = f[i][j];
		}
	printf("%.2lf\n", find_ans(1));
	return 0;
}

Estas son preguntas relativamente simples, y las difíciles no se han hecho, que así sea.

 

Supongo que te gusta

Origin blog.csdn.net/weixin_60360239/article/details/128739721
Recomendado
Clasificación