POJ P2728 Desert King

在这里插入图片描述

analysis

题目要求 ∑ i = 1 n C i × x i ∑ i = 1 n D i × x i \frac{\sum_{i=1}^{n}C_i\times x_i}{\sum_{i=1}^{n}D_i\times x_i} i=1nDi×xii=1nCi×xi的最小值

显然是01分数规划

于是应该先二分一个L,然后按照同样的模板考虑二分

如果存在一组x使得

∑ i = 1 n C i × x i ∑ i = 1 n D i × x i &lt; L ∑ i = 1 n C i × x i &lt; L × ∑ i = 1 n D i × x i \frac{\sum_{i=1}^{n}C_i\times x_i}{\sum_{i=1}^{n}D_i\times x_i}&lt;L\\ \sum_{i=1}^{n}C_i\times x_i&lt;L\times \sum_{i=1}^{n}D_i\times x_i\\ i=1nDi×xii=1nCi×xi<Li=1nCi×xi<L×i=1nDi×xi

∑ i = 1 n ( C i − L × D i ) × x i &lt; 0 \sum_{i=1}^{n}(C_i-L\times D_i)\times x_i&lt;0\\ i=1n(CiL×Di)×xi<0

如果对于所有解x都是

∑ i = 1 n C i × x i ∑ i = 1 n D i × x i &gt; = L ∑ i = 1 n C i × x i &gt; = L × ∑ i = 1 n D i × x i \frac{\sum_{i=1}^{n}C_i\times x_i}{\sum_{i=1}^{n}D_i\times x_i}&gt;=L\\ \sum_{i=1}^{n}C_i\times x_i&gt;=L\times \sum_{i=1}^{n}D_i\times x_i\\ i=1nDi×xii=1nCi×xi>=Li=1nCi×xi>=L×i=1nDi×xi

∑ i = 1 n ( C i − L × D i ) × x i &gt; = 0 \sum_{i=1}^{n}(C_i-L\times D_i)\times x_i&gt;=0\\ i=1n(CiL×Di)×xi>=0

相当于就是要去找最小的 C i − L × D i C_i-L\times D_i CiL×Di

这不就是把边权设为 C i − L × D i C_i-L\times D_i CiL×Di然后跑一个最小生成树吗?

这个题是一个完全图,最好是使用prim算法求解

关于那个二分的最大值:

最长的距离为 1 e 4 \sqrt{1e4} 1e4

最高的高度(花费)为 1 e 7 1e7 1e7

也就是说二分的最大值为 1 e 7 1e7 1e7

于是时间复杂度也就可以算了:

O ( l o g ( 1 e 7 ) × n 2 ) = 32 ∗ 1 e 6 = 1 e 7 O(log{(1e7)}\times n^2)=32*1e6=1e7 O(log(1e7)×n2)=321e6=1e7

稳稳地跑得过

(关于两点间的距离和花费,建议不要写函数,要么存数组,要么用宏实现,不然就会像我一样代码需要卡常数)

(其原因在于代码里面反复调用了O(1)的函数,粗略计算调用次数不下于1000000次,函数调用开销太大,换成宏或数组开销就小了)

(这个东西常数能够大到这个地步也是够了)

code

#include<bits/stdc++.h>
using namespace std;
#define loop(i,start,end) for(register int i=start;i<=end;++i)
#define clean(arry,num) memset(arry,num,sizeof(arry))
#define anti_loop(i,start,end) for(register int i=start;i>=end;--i)
#define ll long long
#define cf(a) ((a)*(a))
template<typename T>void read(T &x){
	x=0;char r=getchar();T neg=1;
	while(r>'9'||r<'0'){if(r=='-')neg=-1;r=getchar();}
	while(r>='0'&&r<='9'){x=(x<<1)+(x<<3)+r-'0';r=getchar();}
	x*=neg;
}
int n;
const int maxn=1000+10;
struct node{double x,y,z;}point[maxn];
//inline double getdis(node a,node b){return sqrt(cf(a.x-b.x)+cf(a.y-b.y));}
//inline double getcost(node a,node b){return abs(a.z-b.z);}
#define getdis(a,b) (sqrt(cf(a.x-b.x)+cf(a.y-b.y)))
#define getcost(a,b) (abs(a.z-b.z))
double dis[maxn];
bool vis[maxn];
double prim(register double L){
	clean(vis,false);
	dis[1]=0;vis[1]=true;
	loop(i,2,n)
		dis[i]=getcost(point[i],point[1])-L*getdis(point[i],point[1]);
	int f=-1;
	double res=0,mindis=1e9;
	loop(T,2,n){
		mindis=1e9;
		loop(i,1,n){
			if(!vis[i]&&dis[i]<mindis){
				mindis=dis[i];
				f=i;
			}
		}
		if(f==-1)break;
		res+=mindis;vis[f]=1;
		loop(i,1,n){
			if(!vis[i])
				dis[i]=min(dis[i],getcost(point[i],point[f])-L*getdis(point[i],point[f]));
		}
	}
	return res;
}
void bin(){
	double L=0,R=1e7,eps=1e-7;
	while(R-L>=eps){
		double mid=(L+R)/2;
		if(prim(mid)<0)
			R=mid;
		else L=mid;
	}
	printf("%.3lf\n",L);
}
int main(){
	#ifndef ONLINE_JUDGE
	freopen("datain.txt","r",stdin);
	#endif
	while(1){
		read(n);
		if(!n)break;
		loop(i,1,n){
			int xi,yi,zi;
			read(xi);read(yi);read(zi);
			point[i].x=(double)xi;
			point[i].y=(double)yi;
			point[i].z=(double)zi;
		}
		bin();
	}
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AndrewMe8211

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值