一开始没理解最优比率生成树为什么要用最小生成树。
书上说的是最大生成树,我一开始觉得是最大生成树,但这样求出来是合法值的最大值,也不是题目上的最小值啊。后来我发现,是在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)−k∗dis(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;
}
}