0/1分数规划

求下式的最大值:

\[\frac{\sum_i^n a_i \times x_i}{\sum_i^n b_i \times x_i} \]

也就是 对任意的x

\[\frac{\sum_i^n a_i \times x_i}{\sum_i^n b_i \times x_i} \le ans \]

二分一个值mid 问题转化是否存在一组x 使

\[\sum_i^n (a_i -b_i \times mid ) \times x_i \ge 0 \]

如果存在 说明二分的值小了 如果不存在 说明二分的值大了

所以一求上面式子的最大值即可
这是0/1分数规划问题的关键: 求出满足题意的最大值

最优比例生成树

每个边有连个权值 求最优比例生成树
沙漠之王

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int N=1010;
const int INF=0x3f3f3f3f;
const double eps=1e-6;
int read()
{
	int x=0,f=0,c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	return f?-x:x;
}

int n; 

struct Point
{
	int x,y,h;
}p[N];
double a[N][N],b[N][N],e[N][N];
double getdis(int x,int y,int x_,int y_){ return sqrt( (x-x_)*(x-x_)+(y-y_)*(y-y_) ); }
double dis[N];
bool vis[N];
//稠密图还真的不能加堆优化 加上堆优化后变成mlogn prim的优势不再显著
//double:: 1e37
bool check(double mid)
{
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			e[i][j]=a[i][j]-mid*b[i][j];
	for(int i=1;i<=n;i++) dis[i]=INF,vis[i]=0;
	dis[1]=0;
	for(int i=1;i<=n;i++)
	{
		int x=0;
		for(int j=1;j<=n;j++)
			if(!vis[j]&&(!x||dis[j]<dis[x])) x=j;//这种查找方式一定要处理第一次查找的情况
		 vis[x]=1;
		 for(int j=1;j<=n;j++)
		 	if(!vis[j]) dis[j]=min(dis[j],e[x][j]);
	}
	double ret=0;
	for(int i=1;i<=n;i++) ret+=dis[i];
	return ret<0;
}

int main()
{
	while( (n=read())!=0)
	{
		for(int i=1;i<=n;i++) p[i].x=read(),p[i].y=read(),p[i].h=read();
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
			{
				a[i][j]=abs(p[i].h-p[j].h); 
				b[i][j]=getdis(p[i].x,p[i].y,p[j].x,p[j].y);
			}	
		double l=0,r=1e11;
		while(r-l>eps)
		{
			double mid=(l+r)/2;
			if(check(mid)) r=mid;
			else l=mid;
		}
		printf("%.3lf\n",r);
	}
	return 0;
}
posted @ 2022-01-13 21:39  __iostream  阅读(67)  评论(0)    收藏  举报