POJ2728 Desert King 最优比率生成树

一开始没理解最优比率生成树为什么要用最小生成树。
书上说的是最大生成树,我一开始觉得是最大生成树,但这样求出来是合法值的最大值,也不是题目上的最小值啊。后来我发现,是在0/1规划二分的意义上理解出错了。
在一般的二分答案中,比如函数是单调递减的,>0的都不是解,<0的都是解,=0的是我们可能要求的解里面的最大值。但是对于0/1规划,二分的是唯一解,>0、<0的都不是解,只有=0的是解。
我们设二分的比率是 k k k,树用 x x x表示,最小生成树用 x m i n x_{min} xmin表示,最大生成树用 x m a x x_{max} xmax表示, F ( k , x ) = c o s t ( x ) − k ∗ d i s ( x ) F(k,x)=cost(x)-k*dis(x) F(k,x)=cost(x)kdis(x)。固定一棵树 x x x F ( k , x ) F(k,x) F(k,x)反比于 k k k F ( k , x ) = 0 F(k,x)=0 F(k,x)=0 k k k是正解。 F ( k , x ) < 0 F(k,x)<0 F(k,x)<0时,说明这棵树的比率比 k k k小; F ( k , x ) > 0 F(k,x)>0 F(k,x)>0时,说明这棵树的比率比 k k k大。

在二分过程中,如果只保证 F ( k , x m a x ) = 0 F(k,x_{max})=0 F(k,xmax)=0,那么 F ( k , x m i n ) < F ( k , x m a x ) F(k,x_{min})<F(k,x_{max}) F(k,xmin)<F(k,xmax),即 F ( k , x m i n ) < 0 F(k,x_{min})<0 F(k,xmin)<0,那么此时 x m i n x_{min} xmin的比率显然比 k k k小,因此 k k k需要继续二分。(此时的 k k k实际上为比例最大值。)

AC代码:

#include <cstdio>
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <iomanip>
#include <cstdlib>
#include <stack>
#include <cstring>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define lep(i,a,b) for(int i=(a);i>=(b);i--) 
#define lepp(i,a,b) for(int i=(a);i>(b);i--)
#define sci(x) scanf("%d",&(x))
#define scl(x) scanf("%lld",&(x))
#define scs(x) scanf("%s",(x))
#define pri(x) printf("%d\n",(x))
#define prl(x) printf("%lld\n",(x))
#define prs(x) printf("%s\n",(x))
#define pdi pair<double,int>
#define pll pair<long long,long long>
#define mp make_pair
#define All(x) x.begin(),x.end() 
#define ms(a,b) memset(a,b,sizeof(a)) 
#define INF 0x3f3f3f3f
#define INFF 0x3f3f3f3f3f3f3f3f
#define multi int T;scanf("%d",&T);while(T--) 
using namespace std;
typedef long long ll;
typedef double db;
const int N=1e3+5;
const int mod=1e9+7;
const db eps=1e-6;                                                                            
const db pi=acos(-1.0);
int n,vis[N];
db z[N][N],w[N][N],v[N][N],dis[N];
struct location{
    int x,y,z;
}c[N];
inline db cal(db a,db b){
    return a*a+b*b;
} 
int main(){
    #ifndef ONLINE_JUDGE
    freopen("D:\\work\\data.in","r",stdin);
    #endif
    while(cin>>n&&n){
        rep(i,1,n){
            cin>>c[i].x>>c[i].y>>c[i].z;
            rep(j,1,i-1){
                z[i][j]=abs(c[i].z-c[j].z);
                w[i][j]=sqrt(cal(c[i].x-c[j].x,c[i].y-c[j].y));
            }
        }
        db l=0,r=100;
        while(r-l>eps){
            db mid=(l+r)/2.0;
            rep(i,1,n){
                dis[i]=1e17;
                rep(j,1,i-1) v[i][j]=v[j][i]=z[i][j]-mid*w[i][j];
                vis[i]=0;
            }
            dis[1]=0;
            db tmp=0,mindis=1e17;
            int pos;
            rep(i,1,n){
                mindis=1e17;
                rep(j,1,n){
                    if(vis[j]) continue;
                    if(dis[j]<mindis){
                        mindis=dis[j];
                        pos=j;
                    }
                }
                tmp+=dis[pos];
                vis[pos]=1;
                rep(j,1,n)
                    if(vis[j]==0&&dis[j]>v[pos][j]) 
                        dis[j]=v[pos][j];
            }
            if(tmp>=0) l=mid;
            else r=mid;
        }
        cout<<fixed<<setprecision(3)<<l<<endl;
    }
}

猜你喜欢

转载自blog.csdn.net/Luowaterbi/article/details/112971587
今日推荐