卧薪尝胆,厚积薄发。
Desert King
Date: Thu Sep 06 20:16:12 CST 2018
In Category:
NoCategory
Description:
每条边有两个值
$a_i$
和
$b_i$
,最小化
$\sum a_i/\sum b_i$
使得图联通。
$1\le m \le 1000000$
Solution:
$01$
分数规划,设二分答案为
$x$
,要判断的就是
$\sum(a_i-xb_i)$
与
$0$
的关系,于是以
$a_i-xb_i$
为边权做最小生成树即可。由于是完全图
$kruskal$
瓶颈在
$n^2\log n$
排序,所以要用
$prim$
。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
#define MAXN 1010
int n;
int x[MAXN],y[MAXN],h[MAXN];
long double d1[MAXN][MAXN],d2[MAXN][MAXN];
long double d[MAXN][MAXN];
long double mind[MAXN];
bool ins[MAXN];
bool check(double x)
{
for(int i = 1;i <= n;++i)
for(int j = 1;j <= n;++j)
d[i][j] = d1[i][j] - x * d2[i][j];
long double res = 0;
for(int i = 0;i <= n;++i)mind[i] = 1000000000;
memset(ins,false,sizeof(ins));
mind[1] = 0;
for(int i = 1;i <= n;++i)
{
int k = 0;
for(int j = 1;j <= n;++j)
if(!ins[j] && mind[j] < mind[k])
k = j;
ins[k] = true;
res += mind[k];
for(int j = 1;j <= n;++j)
{
if(ins[j])continue;
mind[j] = min(mind[j],d[k][j]);
}
}
return res <= 0;
}
int main()
{
while(scanf("%d",&n) && n != 0)
{
for(int i = 1;i <= n;++i)scanf("%d%d%d",&x[i],&y[i],&h[i]);
for(int i = 1;i <= n;++i)
{
for(int j = 1;j <= n;++j)
{
d1[i][j] = abs(h[i] - h[j]);
d2[i][j] = sqrt((long double)(x[i] - x[j]) * (long double)(x[i] - x[j]) + (long double)(y[i] - y[j]) * (long double)(y[i] - y[j]));
}
}
long double l = 0,r = 1000000000,mid;
while(r - l > 1e-6)
{
mid = (l + r) / 2;
if(check(mid))r = mid;
else l = mid;
}
printf("%.3Lf\n",l);
}
return 0;
}
In tag:
算法-01分数规划
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡