poj2728
题意:一个无向图,每条边有两个权值,c和l,要求一个生成树,使得所有边的c的和比上l的和最小。
分析:最优比例生成树。现在要求(c1+...)/(l1+...),设一个比例值变量为r。令r>=(c1+...)/(l1+...)。现在题目转化为求r的最小值。
假设我们对于一个确定的r可以判断该不等式是否可以满足,那么我们可以用二分查找的方法来求r的最小值,因为r猜大了则可满足,猜小了则不可满足。
然而,我们确实可以对于一个确定的r来判定是否可满足不等式,方法如下:
现在r是确定的,相当于已知r。先将不等式整理为如下形式:(r*l1-c1)+...>=0,然后我们使不等式左边尽量大即可。现在不等式左边的的每个括号里都只与一个边有关,把这个括号里的值作为这个边的权值,求图的最大生成树即可使得左边最大。
View Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
usingnamespace 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());
}
return0;
}
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
usingnamespace 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());
}
return0;
}