• 01分数规划学习笔记


    01分数规划学习笔记

    今天 gsh 带着我们复习了一下01分数规划。

    01分数规划就是假设一个物体有两个属性 a,b,同时选择在这个集合中的k个物品,使:

    [v=dfrac{sum^{i=1} _{i<=n} a_i cdot x_i}{sum ^{i=1} _{i<=n} b_i cdot x_i} ,sum_{i=1}^{n}x_i=k ]

    的值最大。

    那么如何能做到呢?看这个式子我们很难看出如何求解,那么将其变形。

    [v cdot sum^{i=1} _{i<=n} b_i cdot x_i- sum^{i=1}_{i<=n} a_icdot x_i=0 ]

    提取公因式

    [sum ^{i=1}_{i<=n} x_i cdot(vcdot b_i-a_i)=0 ]

    那么,我们可以二分一个v,设一个变量

    [c_i=(vcdot b_i-a_i) ]

    sort后选择最大的k个,二分如下。

    	while(r-l>1e-5) {
    			double mid=(l+r)/2;
    			if(check(mid))
    				l=mid;
    			else r=mid;
    		}
    

    然后就有最优比率生成环(用spfa等等判正环),最优比率生成树(最大生成树)求出sumc是否大于0即可。

    附一道题,poj2728,Desert King,最优比率生成树。

    题目大意:有n个村庄,每个村庄有一个高度和坐标,要求建一个生成树,每条边有两个属性是距离与代价,要求单位长度的花费最小 (代价的大小就是这两个村庄的高度差的绝对值)。

    //Writer : Hsz %WJMZBMR%tourist%hzwer
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #include<stack>
    #include<vector>
    #include<cstdlib>
    #include<algorithm>
    #define LL long long
    using namespace std;
    int n;
    const int N=1004;
    int x[N],y[N],z[N];
    bool vis[N];
    double a[N][N],b[N][N],c[N][N],dis[N];//邻接矩阵存图。
    double dist(int d,int e) {
    	return (x[d]-x[e])*(x[d]-x[e])+(y[d]-y[e])*(y[d]-y[e]);
    }
    bool check(double v) {
    	memset(vis,0,sizeof vis);
    	vis[1]=1;
    	for(int i=1; i<=n; i++) dis[i]=b[1][i]-v*a[1][i];
    	double ans=0;
    	for(int i=2; i<=n; i++) {//prim求最小生成树
    		double tp=1061109567;
    		int k;
    		for(int j=2; j<=n; j++)
    			if(!vis[j] and dis[j]<tp) k=j,tp=dis[j];
    		if(k==-1) break;
    		vis[k]=1;
    		ans+=tp;
    		for(int j=2; j<=n; j++) {
    			if(!vis[j] and b[k][j]-v*(a[k][j])<dis[j]) {
    				dis[j]=b[k][j]-v*(a[k][j]);
    			}
    		}
    	}
    	return ans>=0;
    }
    int main() {
    	while(~scanf("%d",&n)&&n) {
    		for(int i=1; i<=n; i++) {
    			scanf("%d%d%d",&x[i],&y[i],&z[i]);
    		}
    		for(int i=1; i<=n; i++)
    			for(int j=1; j<=n; j++)
    				if(i!=j)
    					a[i][j]=sqrt(dist(i,j)),b[i][j]=abs(z[i]-z[j]);
    		double l=0,r=1e9;
    		while(r-l>1e-5) {//二分
    			double mid=(l+r)/2;
    			if(check(mid))
    				l=mid;
    			else r=mid;
    		}
    		printf("%.3lf
    ",l);
    	}
    
    	return 0;
    }
    
    我是咸鱼。转载博客请征得博主同意Orz
  • 相关阅读:
    封装简单的mvc框架
    php中date函数获取当前时间的时区误差解决办法
    PHP中date函数参数详解
    PHP中字符串补齐为定长
    php将xml文件转化为数组:simplexml_load_string
    PHP基于变量的引用实现的树状结构
    EcShop后台添加菜单[步骤]
    Cmd批处理语法实例
    Mysql语句的批量操作[修改]
    HTML前端技术(JS的使用,包括数组和字符串)
  • 原文地址:https://www.cnblogs.com/sdfzhsz/p/9094398.html
Copyright © 2020-2023  润新知