POJ P2728 Desert King

POJ P2728 Desert King

analysis

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

显然是01分数规划

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

如果存在一组x使得

i=1nCi×xii=1nDi×xi&lt;Li=1nCi×xi&lt;L×i=1nDi×xi \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=1n​Di​×xi​∑i=1n​Ci​×xi​​<Li=1∑n​Ci​×xi​<L×i=1∑n​Di​×xi​

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

如果对于所有解x都是

i=1nCi×xii=1nDi×xi&gt;=Li=1nCi×xi&gt;=L×i=1nDi×xi \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=1n​Di​×xi​∑i=1n​Ci​×xi​​>=Li=1∑n​Ci​×xi​>=L×i=1∑n​Di​×xi​

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

相当于就是要去找最小的CiL×DiC_i-L\times D_iCi​−L×Di​

这不就是把边权设为CiL×DiC_i-L\times D_iCi​−L×Di​然后跑一个最小生成树吗?

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

关于那个二分的最大值:

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

最高的高度(花费)为1e71e71e7

也就是说二分的最大值为1e71e71e7

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

O(log(1e7)×n2)=321e6=1e7O(log{(1e7)}\times n^2)=32*1e6=1e7O(log(1e7)×n2)=32∗1e6=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;
}

上一篇:判断文件和目录是否存在,后台命令运行


下一篇:linux命令: sort