HDU4081 Qin Shi Huang's National Road System(最小生成树+思维)

探讨了秦始皇时期,通过最小生成树算法优化全国道路系统,旨在连接所有城市的同时,减少道路建设的成本和对人民的影响。文章深入分析了算法实现细节,包括Prim算法的应用及如何计算魔法路带来的效益最大化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Qin Shi Huang’s National Road System(秦始皇修路)

HERE

Description

During the Warring States Period of ancient China(476 BC to 221 BC), there were seven kingdoms in China ---- they were Qi, Chu, Yan, Han, Zhao, Wei and Qin. Ying Zheng was the king of the kingdom Qin. Through 9 years of wars, he finally conquered all six other kingdoms and became the first emperor of a unified China in 221 BC. That was Qin dynasty ---- the first imperial dynasty of China(not to be confused with the Qing Dynasty, the last dynasty of China). So Ying Zheng named himself “Qin Shi Huang” because “Shi Huang” means “the first emperor” in Chinese.
Qin Shi Huang undertook gigantic projects, including the first version of the Great Wall of China, the now famous city-sized mausoleum guarded by a life-sized Terracotta Army, and a massive national road system. There is a story about the road system:
There were n cities in China and Qin Shi Huang wanted them all be connected by n-1 roads, in order that he could go to every city from the capital city Xianyang.
Although Qin Shi Huang was a tyrant, he wanted the total length of all roads to be minimum,so that the road system may not cost too many people’s life. A daoshi (some kind of monk) named Xu Fu told Qin Shi Huang that he could build a road by magic and that magic road would cost no money and no labor. But Xu Fu could only build ONE magic road for Qin Shi Huang. So Qin Shi Huang had to decide where to build the magic road. Qin Shi Huang wanted the total length of all none magic roads to be as small as possible, but Xu Fu wanted the magic road to benefit as many people as possible ---- So Qin Shi Huang decided that the value of A/B (the ratio of A to B) must be the maximum, which A is the total population of the two cites connected by the magic road, and B is the total length of none magic roads.
Would you help Qin Shi Huang?
A city can be considered as a point, and a road can be considered as a line segment connecting two points.

Input

The first line contains an integer t meaning that there are t test cases(t <= 10).
For each test case:
The first line is an integer n meaning that there are n cities(2 < n <= 1000).
Then n lines follow. Each line contains three integers X, Y and P ( 0 <= X, Y <= 1000, 0 < P < 100000). (X, Y) is the coordinate of a city and P is the population of that city.
It is guaranteed that each city has a distinct location.

Output

For each test case, print a line indicating the above mentioned maximum ratio A/B. The result should be rounded to 2 digits after decimal point.

Sample Input

2
4
1 1 20
1 2 30
200 2 80
200 1 100
3
1 1 20
1 2 30
2 2 40

Sample Output

65.00
70.00

思路

最小生成树的变式
如果没有徐福的魔法,这是一道最小生成树的板子题。给出了各个点x,y坐标,用邻接矩阵(表)(?就是那个map[MAXN][MAXN]数组直接存图),边的数量最多499500条,想到用Prim算法。
再看徐福的魔法:让一条路的没有花费,目标是使惠及到的人民与除去魔法路的总路长的比值最大。
考虑两点:1、分子越大。即:惠及到的人民越多越好
2、分母越小。即路径越短越好(砍掉的树枝越越长越好)
对于第一点:依次枚举两不同点,时间复杂度大概在O(n2
对于第二点,建树时记录每条边,我采取的方法是再开一个数组Path[MAXN][MAXN]用于记录 i —> j 的最大值。
转移方程:path[ i ][ u ] = path[ u ][ i ] = max(path[ i ][ pre[ u ] ],dist[ u ]);可以用一些动态规划的感觉看这个方程。设直接与 u 相连的点为 j = pre[u],比较 i 与 j 之间若干树枝的最大值 与 map[u][j]的大小,始终储存最大的,即能保证储存的是任意两点之间的“最长树枝”

如何计算:

对于枚举到的点 i , j
均在最小树上:A/B = (node[i].peo+node[j].peo)/(B-map[i][j]);
不在最小树上:A/B = (node[i].peo+node[j].peo)/(B-path[i][j]);

代码

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <cstring>
#include <cmath>
#define MAXN 1005
#define INF 1500.0
using namespace std;
struct coun		//储存国家 
{
	int x;
	int y;
	int peo;
} node[MAXN];
int n=0,m=0,cnt=0,pre[MAXN];
double dist[MAXN],map[MAXN][MAXN],path[MAXN][MAXN];//map用于存地图,path用于记录路径 
//Prim算法(便于记录一些过程量) 
double Prim()
{
	//初始化 
	double ans=0.0;
	for (int i=0; i<n; i++)
	{
		dist[i]=map[0][i];
		pre[i]=i;
	}
	for (int i=0; i<n-1; i++)
	{
		//找到最近的点 
		int u=-1;
		double temp=INF;
		for (int j=1; j<n; j++)
		{
			if (
			    dist[j]
			    &&dist[j]<temp)
			{
				u=j;
				temp=dist[j];
			}
		}
		//更新距离表
		ans+=dist[u];
		for (int j=0; j<n; j++)
		{
			/*注意path和map*/ 
			//if  j在树上 && j!=u 
			if (!dist[j]&&j!=u)
			{
				path[j][u]=path[u][j]=max(path[j][pre[u]],dist[u]);	//记录j到u的最长路径 
			}
			else if (j!=u&&dist[j]&&map[u][j]<dist[j])
			{
				dist[j]=map[u][j];
				pre[j]=u;//j点和u相连入树
			}
		}
		dist[u]=0.0;
	}
	return ans;
}
int main()
{
	int t;
	cin>>t;
	while (t--)
	{
		cin>>n;
		for (int i=0; i<n; i++)
		{
			cin>>node[i].x>>node[i].y>>node[i].peo;
		}
		for (int i=0; i<n-1; i++)
		{
			map[i][i]=0;
			for (int j=i+1; j<n; j++)
			{
				map[i][j]=map[j][i]=sqrt((node[i].x-node[j].x)*(node[i].x-node[j].x)+(node[i].y-node[j].y)*(node[i].y-node[j].y));
				path[i][j]=path[j][i]=0;
			}
		}
		double B=Prim();
		double ans=-1.0;
		for (int i=0; i<n-1; i++)
		{
			for (int j=i+1; j<n; j++)
			{
				//两种建桥的方式 
				if (pre[i]==j||pre[j]==i)
				{
					ans=max(ans,(node[i].peo+node[j].peo)/(B-map[i][j]));
				}
				else
				{
					ans=max(ans,(node[i].peo+node[j].peo)/(B-path[i][j]));
				}
			}
		}
		cout<<fixed<<setprecision(2)<<ans<<endl;
	}
	return 0;
}

tips:

感谢大佬题解给的思路和详解,附上链接。
https://www.cnblogs.com/zk1431043937/p/7751599.html

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值