poj 2728 Desert King(最优比率生成树,01分数规划)

http://poj.org/problem?id=2728

大致题意:有n个村庄,输入每个村庄的位置和高度,这n个村庄要连在一起,村与村之间的长度为他们之间的欧几里得距离,花费是两村之间的高度差,要求连在一起的花费和与距离和之比的最小值。

思路:明显的最优比率生成树。二分答案λ,每条边重新赋权c[i] - λd[i] ,因为要求比值最小,那么对于所有的生成树,它们的f[λ]必须>=0,所以只需求得基于最小生成树的f‘[λ],当f‘[λ]
= 0时即找到了正解λ*。

二分:

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#define LL long long
#define _LL __int64
#define eps 1e-7
using namespace std;
const _LL INF = 1e18;
const int maxn = 1010;

struct node
{
	int x,y,z;
}p[maxn];

int n;
double Map[maxn][maxn];

double cal(int i, int j)
{
	return sqrt( 1.0*(p[i].x - p[j].x)*(p[i].x - p[j].x) + 1.0*(p[i].y - p[j].y)*(p[i].y - p[j].y) );
}

double prim(double mid)
{
	double dis[maxn];
	int vis[maxn];
	double sum = 0;
	memset(vis,0,sizeof(vis));
	for(int i = 1; i <= n; i++)
		dis[i] = abs(p[i].z - p[1].z) - Map[1][i] * mid;

	vis[1] = 1;
	for(int i = 1; i <= n-1; i++)
	{
		double Min = INF;
		int pos = -1;
		for(int j = 1; j <= n; j++)
		{
			if(!vis[j] && dis[j] < Min)
			{
				Min = dis[j];
				pos = j;
			}
		}
		if(pos == -1)
			break;
		sum += Min;
		vis[pos] = 1;

		double tmp;
		for(int j = 1; j <= n; j++)
		{
			tmp = abs(p[pos].z - p[j].z) - Map[pos][j] * mid;
			if(!vis[j] && dis[j] > tmp)
				dis[j] = tmp;
		}
	}

	return sum;
}

int main()
{
	while(~scanf("%d",&n) && n)
	{
		for(int i = 1; i <= n; i++)
			scanf("%d %d %d",&p[i].x,&p[i].y,&p[i].z);

		for(int i = 1; i <= n; i++)
		{
			for(int j = 1; j <= n; j++)
				Map[i][j] = cal(i,j);
		}

		double l = 0.0, r = 40.0;
		double mid;
		while(fabs(r-l) > eps)
		{
			mid = (l+r)/2;
			if( prim(mid) >= 0)
				l = mid;
			else r = mid;
		}
		printf("%.3f\n",mid);
	}
	return 0;
}

迭代

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#define LL long long
#define _LL __int64
#define eps 1e-7
using namespace std;
const _LL INF = 1e18;
const int maxn = 1010;

struct node
{
	int x,y,z;
}p[maxn];

int n;
double Map[maxn][maxn];

double cal(int i, int j)
{
	return sqrt( 1.0*(p[i].x - p[j].x)*(p[i].x - p[j].x) + 1.0*(p[i].y - p[j].y)*(p[i].y - p[j].y) );
}

double prim(double mid)
{
	double cost,len,sum;
	double dis[maxn];
	int vis[maxn];
	int pre[maxn];

	sum = 0;
	cost = 0;
	len = 0;
	memset(vis,0,sizeof(vis));
	memset(pre,-1,sizeof(pre));
	for(int i = 1; i <= n; i++)
	{
		dis[i] = abs(p[i].z - p[1].z) - Map[1][i] * mid;
		pre[i] = 1;
	}
	vis[1] = 1;

	for(int i = 1; i <= n-1; i++)
	{
		double Min = INF;
		int pos = -1;
		for(int j = 1; j <= n; j++)
		{
			if(!vis[j] && dis[j] < Min)
			{
				Min = dis[j];
				pos = j;
			}
		}
		if(pos == -1)
			break;
		sum += Min;
		cost += abs(p[ pre[pos] ].z - p[pos].z);
		len += Map[pre[pos]][pos];
		vis[pos] = 1;

		double tmp;
		for(int j = 1; j <= n; j++)
		{
			tmp = abs(p[pos].z - p[j].z) - Map[pos][j] * mid;
			if(!vis[j] && dis[j] > tmp)
			{
				dis[j] = tmp;
				pre[j] = pos;
			}
		}
	}
	return cost/len;
}

int main()
{
	while(~scanf("%d",&n) && n)
	{
		for(int i = 1; i <= n; i++)
			scanf("%d %d %d",&p[i].x,&p[i].y,&p[i].z);

		for(int i = 1; i <= n; i++)
		{
			for(int j = 1; j <= n; j++)
				Map[i][j] = cal(i,j);
		}

		double l = 0.0,r;
		while(1)
		{
			r = prim(l);
			if(fabs(r-l) < eps) break;
			l = r;
		}
		printf("%.3f\n",r);
	}
	return 0;
}

poj 2728 Desert King(最优比率生成树,01分数规划)

时间: 2024-08-09 06:33:58

poj 2728 Desert King(最优比率生成树,01分数规划)的相关文章

POJ 2728 Desert King (最优比率生成树---01分数规划)

题目地址:POJ 2728 01分数规划的应用之一-最优比率生成树. 跟普通的01分数规划类似,只是这题的验证函数改成了最小生成树来验证.弱用的迭代法. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map>

poj 2728(Desert King) 最优比例生成树 (分数规划)

这题是最小生成树的一种扩展,就是求一棵树  使得 k =sigma(cost)/ sigma(len)  最小.   其中cost 为每条边花费,len为长度.  这实际上就是一个最优比例生成树.最优比例生成树的求解使用了分数规划的方法.  我们先任取k,假设k是最小值,那么sigma(ccost)-k*sigma(len)==0  .那么我们就新建图边权 为  ccosti-k*leni  .求一次最小生成树,如果生成树权值小于0,那么书名其实k还是有减小的空间的,否则,k不可能是最小.这样我

POJ 2728 Desert King 最优比率生成树

Desert King Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 20978   Accepted: 5898 [Description] David the Great has just become the king of a desert country. To win the respect of his people, he decided to build channels all over his co

POJ 2728 Desert King(最优比率生成树 01分数规划)

http://poj.org/problem?id=2728 题意: 在这么一个图中求一棵生成树,这棵树的单位长度的花费最小是多少? 思路: 最优比率生成树,也就是01分数规划,二分答案即可,题目很简单,因为这题是稠密图,所以用prim算法会好点. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector>

Desert King (poj 2728 最优比率生成树 0-1分数规划)

Language: Default Desert King Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 22113   Accepted: 6187 Description David the Great has just become the king of a desert country. To win the respect of his people, he decided to build channels

POJ 2728 Desert King 最优比例生成树

最优比例生成树,迭代方法..... Desert King Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 21086   Accepted: 5916 Description David the Great has just become the king of a desert country. To win the respect of his people, he decided to build channels

ZOJ 2728 Desert King(最优比例生成树)

Desert King Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 20586   Accepted: 5777 Description David the Great has just become the king of a desert country. To win the respect of his people, he decided to build channels all over his coun

POJ2728 最小比率生成树/0-1分数规划/二分/迭代(迭代不会)

用01分数规划 + prime + 二分 竟然2950MS惊险的过了QAQ 前提是在TLE了好几次下过的 = = 题目意思:有n个村庄,村庄在不同坐标和海拔,现在要对所有村庄供水,只要两个村庄之间有一条路即可,建造水管距离为坐标之间的欧几里德距离,费用为海拔之差,现在要求方案使得费用与距离的比值最小,很显然,这个题目是要求一棵最优比率生成树. 解题思路: 对答案进行二分,当把代进去的答案拿来算最小生成树的时候,一旦总路径长度为0,就是需要的答案. 0-1规划是啥? 概念有带权图G, 对于图中每条

【POJ】【2728】 Desert King 最优比率生成树

题意:给出每个点的坐标(x,y,z),两点间距离是x,y的直线距离,边权为z差,求∑边权 / ∑距离 的最小值. 最优比率生成树!(分数规划) 就是根据分数规划的思想建树,每次看得到的总和是正是负. 二分代码: #include<string.h> #include<stdio.h> #include<stdlib.h> #include<math.h> #define N 1010 typedef struct KSD { int x,y,z; }ksd;

【POJ2728】Desert King 最优比率生成树

题目大意:给定一个 N 个点的无向完全图,边有两个不同性质的边权,求该无向图的一棵最优比例生成树,使得性质为 A 的边权和比性质为 B 的边权和最小. 题解:要求的答案可以看成是 0-1 分数规划问题,即:选定一个数 mid,每次重新构建边权为 \(a[i]-mid*b[i]\) 的图,再在图上跑一遍最小生成树(这里由于是完全图,应该采用 Prim 算法)判断最小值和给定判定的最小值的关系即可,这里为:若最小值大于 mid,则下界提高,否则上界下降. 代码如下 #include<cmath>