poj 2728(迭代+prime)

01整数规划有两种解决方法:二分和迭代,二分效率低,迭代容易卡精度。。。。。

这个题二分的话。。貌似会花好长时间。。。。网友是这么说的。。。。然后学了一下迭代。。。。。200++过的。。。

 0-1分数规划

设x[i]等于1或0, 表示边e[i]是否属于生成树.

则我们所求的比率 r = ∑(benifit[i] * x[i]) / ∑(cost[i] * x[i]), 0≤i<m .

为了使 r 最大, 设计一个子问题---> 让 z = ∑(benifit[i] * x[i]) - l * ∑(cost[i] * x[i]) = ∑(d[i] * x[i]) 最大 (d[i] = benifit[i] - l * cost[i]) , 并记为z(l). 我们可以兴高采烈地把z(l)看做以d为边权的最大生成树的总权值.

然后明确两个性质:

 1.  z单调递减

  证明: 因为cost为正数, 所以z随l的减小而增大.

 2.  z( max(r) ) = 0

  证明: 若z( max(r) ) < 0, ∑(benifit[i] * x[i]) - max(r) * ∑(cost[i] * x[i]) < 0, 可化为 max(r) < max(r). 矛盾;

          若z( max(r) ) >= 0, 根据性质1, 当z = 0 时r最大. 

到了这个地步, 七窍全已打通, 喜欢二分的上二分, 喜欢Dinkelbach的就Dinkelbach.

讲解转自 http://www.cnblogs.com/lotus3x/archive/2009/03/21/1418480.html 


#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define inf 1000000000.00
#define N 1010
int x[N],y[N],z[N],pre[N],vis[N];
double cst[N][N],len[N][N],maze[N][N],dis[N];
double prim(int n,double mid){
    int i,j,dj;
    double ta=0,tb=0,k;
    for(i=1;i<n;i++)
        for(j=i+1,maze[i][i]=inf;j<=n;j++)
            maze[i][j]=maze[j][i]=cst[i][j]-len[i][j]*mid;
    for(i=1;i<=n;i++)
        pre[i]=1,vis[i]=0,dis[i]=maze[1][i];
    dis[1]=0,vis[1]=1;
    for(i=1;i<n;i++){
        k=inf;
        for(j=1;j<=n;j++)
            if(!vis[j] && k>dis[j]){
                k=dis[j],dj=j;
            }
        ta+=cst[pre[dj]][dj];
        tb+=len[pre[dj]][dj];
        vis[dj]=1;
        for(j=1;j<=n;j++)
            if(!vis[j] && dis[j]>maze[dj][j])
                dis[j]=maze[dj][j],pre[j]=dj;
    }
    return ta/tb;
}
int main(){
    int n,i,j;
    double ans,tmp;
    while(scanf("%d",&n)!=-1 && n){
        for(i=1;i<=n;i++)
            scanf("%d%d%d",&x[i],&y[i],&z[i]);
        for(i=1;i<n;i++)
            for(j=i+1,cst[i][i]=len[i][i]=inf;j<=n;j++){
                cst[i][j]=cst[j][i]=(double)abs(z[i]-z[j]);
                len[i][j]=len[j][i]=sqrt((double)(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
            }
        tmp=1.0,ans=prim(n,tmp);
        while(fabs(ans-tmp)>0.00001){
            tmp=ans,ans=prim(n,tmp);
        }
        printf("%.3lf\n",ans);
    }
    return 0;
}


你可能感兴趣的:(ini)