Optimal ratio spanning tree (0 / 1 score planning + dichotomy + minimum spanning tree)

Posted by jimpat on Fri, 21 Jan 2022 12:52:22 +0100

Title Description

David the great has just become king of a desert country. In order to win the respect of the people, he decided to build channels all over the country to supply water to each village. The villages connected to his capital village will be watered. As the master of the country and the symbol of wisdom, he needs to build the channel in the most elegant way.

After several days of research, he finally came up with his own plan. He wants to minimize the average cost per mile of access. In other words, the ratio of the total cost to the total length of the channel must be minimized. He only needs to establish the necessary channels to transport water to all villages, which means that there is only one way to connect each village to the capital.

His engineers surveyed the whole country and recorded the location and height of each village. All access roads must pass between the two villages and be built horizontally. Because the altitude of each two villages is different, they concluded that each channel between the two villages needs a vertical water elevator to carry water or let water flow down. The length of the passage is the horizontal distance between the two villages. The cost of access is the height of the lift. You should note that each village can't share a lift at different heights and different channels. The channels can intersect safely, and no three villages are on the same line.

As King David's chief scientist and programmer, you need to find the best solution to build channels.

Introduction to the topic

The coordinates and elevations of n points are given. The length of any two points connected to the edge is the linear distance between the two points (Pythagorean theorem), and the cost of the edge is the difference between the elevations. We hope to find a spanning tree and minimize it
∑ i = 1 n − 1 c o s t [ i ] ∑ i = 1 n − 1 d i s [ i ] \frac{\sum_{i=1}^{n-1}{cost[i]}}{\sum_{i=1}^{n-1}{dis[i]}} ∑i=1n−1​dis[i]∑i=1n−1​cost[i]​
among i i i represents each edge of the spanning tree, c o s t [ i ] cost[i] cost[i] stands for the second i i The cost of i edge, d i s [ i ] dis[i] dis[i] indicates the second i i i length of edges

Problem solving ideas

Consider 0 / 1 score programming
Because Ben konjac can't Dinkelbach, he can only write two points
A real number is divided into two w w w, see if there can be a spanning tree to make
∑ i = 1 n − 1 c o s t [ i ] ∑ i = 1 n − 1 d i s [ i ] ≤ w \frac{\sum_{i=1}^{n-1}{cost[i]}}{\sum_{i=1}^{n-1}{dis[i]}}\leq{w} ∑i=1n−1​dis[i]∑i=1n−1​cost[i]​≤w
∑ i = 1 n − 1 c o s t [ i ] ≤ w × ∑ i = 1 n − 1 d i s [ i ] \sum_{i=1}^{n-1}{cost[i]}\leq{w}\times\sum_{i=1}^{n-1}{dis[i]} i=1∑n−1​cost[i]≤w×i=1∑n−1​dis[i]
∑ i = 1 n − 1 c o s t [ i ] − w × ∑ i = 1 n − 1 d i s [ i ] ≤ 0 \sum_{i=1}^{n-1}{cost[i]}-{w}\times\sum_{i=1}^{n-1}{dis[i]}\leq{0} i=1∑n−1​cost[i]−w×i=1∑n−1​dis[i]≤0
That is, turn each edge into c o s t [ i ] − w × d i s [ i ] cost[i]-{w}\times{dis[i]} cost[i]−w×dis[i]
Then find the minimum spanning tree. If the sum of edge weights is less than 0, turn down w, otherwise turn up w
The code is as follows

#include<bits/stdc++.h>
using namespace std;
const int N=1005;
double cost[N][N];
double len[N][N];
double dis[N];
int x[N],y[N],h[N];
bool vis[N];
int n;
double calc(int a,int b)
{
	return sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));
}
inline int read()
{
	int X=0; bool flag=1; char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
	while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
	if(flag) return X;
	return ~(X-1);
}
bool check(double w)
{
	double sum=0.000;
	for(int i=1;i<=n;i++)
	{
		dis[i]=cost[1][i]-len[1][i]*w;	
	}

	memset(vis,0,sizeof(vis));
	vis[1]=1;
	for(int t=2;t<=n;t++)
	{
		double minx=1e9+7;
		int pos=-1;
		for(int i=1;i<=n;i++)
		{
			if(vis[i]) continue;
			if(dis[i]<minx)
			{
				minx=dis[i];
				pos=i;
			}
		}
		vis[pos]=1;
		sum+=minx;
		for(int i=1;i<=n;i++)
		{
			if(vis[i]) continue;
			if(dis[i]>cost[pos][i]-len[pos][i]*w)
			{
				dis[i]=cost[pos][i]-len[pos][i]*w;
			}
		}
	}
	if(sum-0<0.000) return 1;
	return 0;
}
int main()
{
	freopen("king.in","r",stdin);
	freopen("king.out","w",stdout);
	while(n=read())
	{			
		for(int i=1;i<=n;i++)
		{
			x[i]=read();
			y[i]=read();
			h[i]=read();
		}
		for(int i=1;i<=n;i++)
		{
			for(int j=i+1;j<=n;j++)
			{
				len[j][i]=len[i][j]=calc(i,j);
				cost[j][i]=cost[i][j]=fabs(h[i]-h[j]);
			}
		}
		double l=0.000,r=100.000,mid,ans;
		while(r-l>1e-6)
		{
			mid=(l+r)/2;
			if(check(mid))
			{
				ans=mid;
				r=mid;
			}
			else l=mid;
		}
	printf("%.3lf\n",ans);	
	}
	return 0;
}

Topics: Graph Theory