一.题目链接:
POJ-2728
二.题目大意:
给定一张 N 个点、M 条边的无向图,图中每条边 e 都有一个收益 Ce 和 一个成本 Re。
求该图的一颗生成树 T,最大化
三.分析:
0/1分数规划 + prim check
详见代码.
四.代码实现:
#include <bits/stdc++.h>
using namespace std;
const int M = (int)1e3;
const double eps = 1e-6;
int n;
int x[M + 5], y[M + 5], z[M + 5];
double dis[M + 5][M + 5];
double cost[M + 5][M + 5];
double d[M + 5];
bool vis[M + 5];
double cal_dis(int x1, int y1, int x2, int y2)
{
return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
bool prim(double mid)
{
for(int i = 1; i <= n; ++i)
{
d[i] = cost[1][i] - dis[1][i] * mid;
vis[i] = 0;
}
d[1] = 0;
vis[1] = 1;
for(int i = 1; i < n; ++i)
{
int x = 0;
for(int j = 1; j <= n; ++j)
{
if(!vis[j] && (x == 0 || d[j] < d[x]))
x = j;
}
vis[x] = 1;
for(int y = 1; y <= n; ++y)
{
if(!vis[y])
d[y] = min(d[y], cost[x][y] - dis[x][y] * mid);
}
}
double sum = 0;
for(int i = 1; i <= n; ++i)
sum += d[i];
return sum >= 0;
}
int main()
{
while(~scanf("%d", &n) && n)
{
for(int i = 1; i <= n; ++i)
scanf("%d %d %d", &x[i], &y[i], &z[i]);
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j <= n; ++j)
{
dis[i][j] = cal_dis(x[i], y[i], x[j], y[j]);
cost[i][j] = fabs(z[i] - z[j]);
}
}
double l = 0, r = 100.0, mid;
while(r - l > eps)
{
mid = (l + r) / 2;
if(prim(mid))
l = mid;
else
r = mid;
}
printf("%.3f\n", r);
}
return 0;
}