次小生成树 配题(HDU 4081)

次小生成树:在最小生成树(MST)的基础上求得。

算法步骤:

  • 基础:求出最小生成树,并且标记最小生成树的所有边
  • 将一个不是最小生成树的边加入到最小生成树中,此时有 N 条边( N 个点),必定存在一个“环”,现在需要去除“环”上一条边使之成为一课生成树。
  • 在“环”中去除的边为除了加入边以外的权值最大的边(因为除了次小,就是最小)。
  • 枚举不在最小生成树上的每一条边,将其进行2、3步操作,然后选择更改后权值最小的生成树,该生成树为次小生成树。

配题:HDU 4081

题意:无向图,有 N 个点,每个点的坐标和该点具有的人口数告诉你,秦始皇想将N个点连通起来,用最小的代价去铺路(总里程数最小),有一个巫师,可以将一条路的代价将为 0(巫师选中的这条路必须被建造)。求 一条路的一个特殊比值 \frac{A}{B}=\frac{popular[city_u]+popular[city_v]}{totalroad-edge_{uv}}的最大值。

思想:

  • totalroad显然是最小生成树总权值。
  • 如果巫师选中的路正好在最小生成树上,那么edge_{uv}=MST_{uv}
  • 如果巫师选中的路不在最小生成树上,那么edge_{uv}=SecMST_{uv},此时变成了次小生成树的一个子问题,添加uv之后,去除环中的除(uv)以外的最大边权的边。
  • 选出比值最大的作为输出即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<cmath>
#include<iomanip>
#define inf 0x7fffffff
using namespace std;
const int maxn = 1005;
struct POINT
{
	double x, y;
	int p;
}point[maxn];
struct NODE
{
	int v;
	double dis;
};
vector<NODE>graph[maxn];
int n;
double sum;
double dp[maxn][maxn];
bool used[maxn][maxn];

double cal_dis(POINT& p1, POINT& p2)
{
	return sqrt((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y));
}

double Max(double x, double y)
{
	if (x > y) return x;
	return y;
}

double Prim(int source)
{
	double dis[maxn];
	bool vis[maxn];
	double mindis;
	double sum = 0;
	int father[maxn];
	int pos;
	
	memset(vis, false, sizeof(vis));
	memset(dis, inf, sizeof(dis));
	memset(dp, 0, sizeof(dp));
	memset(used, false, sizeof(used));
	
	for (int i = 0; i < graph[source].size(); i++)
	{
		int v = graph[source][i].v;
		dis[v] = graph[source][i].dis;
		father[v] = source;

	}
	vis[source] = true;
	
	for (int k = 1; k < n; k++)
	{
		mindis = inf;
		for (int j = 1; j <= n; j++)
		{
			if (!vis[j] && dis[j] < mindis)
			{
				mindis = dis[j];
				pos = j;
			}
		}
		
		sum += mindis;
		vis[pos] = true;
		used[father[pos]][pos] = used[pos][father[pos]] = true;
		
		for (int j = 0; j < graph[pos].size(); j++)
		{
			int v = graph[pos][j].v;
			double w = graph[pos][j].dis;
			if (vis[v])
			{
				dp[pos][v] = dp[v][pos] = Max(dis[pos], dp[father[pos]][v]);
			}
			else
			{
				if (dis[v] > w)
				{
					dis[v] = w;
					father[v] = pos;
				}
			}
		} 
	}
	return sum;
}

int main()
{
	int T;
	cin>> T;
	while (T--)
	{
		cin>> n;
		for (int i = 1; i <= n; i++)
		{
			cin>> point[i].x>> point[i].y>> point[i].p;
			graph[i].clear();
		}
		for (int i = 1; i <= n; i++)
		{
			for (int j = i+1; j <= n; j++)
			{
				double dis = cal_dis(point[i], point[j]);
				NODE node;
				node.v = j;
				node.dis = dis;
				graph[i].push_back(node);
				node.v = i;
				graph[j].push_back(node);
			} 
		}
		double mst_sum = Prim(1);
		double res = -1;
		for (int i = 1; i <= n; i++)
		{
			for (int j = 0; j < graph[i].size(); j++)
			{
				int u = i;
				int v = graph[i][j].v;
				int w = graph[i][j].dis;
				if (used[u][v])
				{
					res = Max(res, (point[u].p + point[v].p)*1.0/(mst_sum - w));
				}
				else
				{
					res = Max(res, (point[u].p + point[v].p)*1.0/(mst_sum - dp[u][v]));
				}
			}
		}
		cout<< fixed<< setprecision(2);
		cout<< res<< endl;
	}
	return 0;
}
发布了331 篇原创文章 · 获赞 135 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/Triple_WDF/article/details/102979791