您的位置:首页 > 其它

poj 2728(迭代+prime)

2011-10-08 15:02 155 查看
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.
讲解转自/article/5851025.html

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define inf 1000000000.00
#define N 1010
int x
,y
,z
,pre
,vis
;
double cst

,len

,maze

,dis
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: