题意:一个无向图,每条边有两个权值,c和l,要求一个生成树,使得所有边的c的和比上l的和最小。
分析:最优比例生成树。现在要求(c1+...)/(l1+...),设一个比例值变量为r。令r>=(c1+...)/(l1+...)。现在题目转化为求r的最小值。
假设我们对于一个确定的r可以判断该不等式是否可以满足,那么我们可以用二分查找的方法来求r的最小值,因为r猜大了则可满足,猜小了则不可满足。
然而,我们确实可以对于一个确定的r来判定是否可满足不等式,方法如下:
现在r是确定的,相当于已知r。先将不等式整理为如下形式:(r*l1-c1)+...>=0,然后我们使不等式左边尽量大即可。现在不等式左边的的每个括号里都只与一个边有关,把这个括号里的值作为这个边的权值,求图的最大生成树即可使得左边最大。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include
<
iostream
>
#include < cstdio >
#include < cstdlib >
#include < cstring >
#include < cmath >
using namespace std;
#define maxn 1005
#define eps 0.0001
#define inf 1000000000
struct Village
{
int x, y, z;
} village[maxn];
double dist[maxn][maxn], map[maxn][maxn], mindist[maxn];
int height[maxn][maxn], n;
bool vis[maxn];
double getdist( const Village & a, const Village & b)
{
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
void input()
{
for ( int i = 0 ; i < n; i ++ )
scanf( " %d%d%d " , & village[i].x, & village[i].y, & village[i].z);
for ( int i = 0 ; i < n; i ++ )
for ( int j = i + 1 ; j < n; j ++ )
{
dist[i][j] = dist[j][i] = getdist(village[i], village[j]);
height[i][j] = height[j][i] = abs(village[i].z - village[j].z);
}
}
void makemap( double mid)
{
for ( int i = 0 ; i < n; i ++ )
for ( int j = i + 1 ; j < n; j ++ )
map[j][i] = map[i][j] = - mid * dist[i][j] + height[i][j];
}
double prim( double dist[])
{
double ans = 0 ;
for ( int i = 0 ; i < n; i ++ )
dist[i] = inf;
memset(vis, 0 , sizeof (vis));
dist[ 0 ] = 0 ;
while ( 1 )
{
double mindist = inf;
int mini = - 1 ;
for ( int i = 0 ; i < n; i ++ )
if (dist[i] < mindist && ! vis[i])
{
mindist = dist[i];
mini = i;
}
if (mini == - 1 )
return ans;
vis[mini] = true ;
ans += mindist;
for ( int i = 0 ; i < n; i ++ )
if ( ! vis[i] && map[mini][i] < dist[i])
dist[i] = map[mini][i];
}
}
double binarysearch()
{
double l = 0 , r = 1000000000 ;
while (r - l > eps)
{
double mid = (l + r) / 2 ;
makemap(mid);
double temp = prim(mindist);
if (temp >= 0 )
l = mid;
else
r = mid;
}
return l;
}
int main()
{
// freopen("D:\\t.txt", "r", stdin);
while (scanf( " %d " , & n) != EOF && n != 0 )
{
input();
printf( " %.3f\n " , binarysearch());
}
return 0 ;
}
#include < cstdio >
#include < cstdlib >
#include < cstring >
#include < cmath >
using namespace std;
#define maxn 1005
#define eps 0.0001
#define inf 1000000000
struct Village
{
int x, y, z;
} village[maxn];
double dist[maxn][maxn], map[maxn][maxn], mindist[maxn];
int height[maxn][maxn], n;
bool vis[maxn];
double getdist( const Village & a, const Village & b)
{
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
void input()
{
for ( int i = 0 ; i < n; i ++ )
scanf( " %d%d%d " , & village[i].x, & village[i].y, & village[i].z);
for ( int i = 0 ; i < n; i ++ )
for ( int j = i + 1 ; j < n; j ++ )
{
dist[i][j] = dist[j][i] = getdist(village[i], village[j]);
height[i][j] = height[j][i] = abs(village[i].z - village[j].z);
}
}
void makemap( double mid)
{
for ( int i = 0 ; i < n; i ++ )
for ( int j = i + 1 ; j < n; j ++ )
map[j][i] = map[i][j] = - mid * dist[i][j] + height[i][j];
}
double prim( double dist[])
{
double ans = 0 ;
for ( int i = 0 ; i < n; i ++ )
dist[i] = inf;
memset(vis, 0 , sizeof (vis));
dist[ 0 ] = 0 ;
while ( 1 )
{
double mindist = inf;
int mini = - 1 ;
for ( int i = 0 ; i < n; i ++ )
if (dist[i] < mindist && ! vis[i])
{
mindist = dist[i];
mini = i;
}
if (mini == - 1 )
return ans;
vis[mini] = true ;
ans += mindist;
for ( int i = 0 ; i < n; i ++ )
if ( ! vis[i] && map[mini][i] < dist[i])
dist[i] = map[mini][i];
}
}
double binarysearch()
{
double l = 0 , r = 1000000000 ;
while (r - l > eps)
{
double mid = (l + r) / 2 ;
makemap(mid);
double temp = prim(mindist);
if (temp >= 0 )
l = mid;
else
r = mid;
}
return l;
}
int main()
{
// freopen("D:\\t.txt", "r", stdin);
while (scanf( " %d " , & n) != EOF && n != 0 )
{
input();
printf( " %.3f\n " , binarysearch());
}
return 0 ;
}