uvaLive5713

修建道路使得n个点任意两点之间都可以连通,每个点有都有一定的人口,现在可以免费修一条道路,

A是免费修的道路两端结点的人口之和, B的其它不是免费修道路的长度的总和

要求的是A/B的最短值。

B其实就是最小生成树删除一条边只有的权值之和B。 只要我们知道生成树上任意两点之间的最长边,那么只要在这两点之间修一条边,

然后删除最长边,它还是一棵树。 而已这时候的权值之和是B-maxCost[u][v]

那么 答案就是min{p[u][v] / (B-maxCost[u][v])} , 枚举u,v的时间复杂度是O(n*n)。

至于得到maxCost[u][v] 只要在得到最小生成树之后,一遍dfs就可以求出

求解的方法是:当访问一个新节点时,计算所有已经访问过的结点到这个结点的最小权值

max[u][x] = maxCost[x][u] = max(maxCost[x][fa],edge(u,fa))

u是当前访问的结点,fa是u的父亲, x是所有已经访问过的结点。

(其实就是两个嵌套的循环,只不过是在树上循环罢了)

总的时间复杂度是n*n + e*loge     常数没有计算进去。

n*n和eloge 最大时都是1000多w, 3s的时间,足够了

 #include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
const int INF = <<;
/* */
const int N = + ;
struct Edge
{
int form, to, p;
double dist;
bool operator<(const Edge&rhs)const
{
return dist < rhs.dist;
}
}a[N*N];
int x[N], y[N], p[N];
int father[N];
double maxCost[N][N];
int p2[N][N];
vector<Edge> g[N];
vector<int> st;
int find(int x)
{
if (x == father[x])
return x;
return father[x] = find(father[x]);
}
double kruskal(int n)
{
double sum = ;
for (int i = ; i < n; ++i)
{
int fx = find(a[i].form);
int fy = find(a[i].to);
if (fx != fy)
{
//记录生成树,用来等下dfs
g[a[i].form].push_back(a[i]);
swap(a[i].form, a[i].to);
g[a[i].form].push_back(a[i]);
sum += a[i].dist;
father[fx] = fy;
}
}
return sum;
} /*
这个dfs其实就是给定一棵树,然后求任意两点之间的最大边权, 因为是任意两点, 那么时间复杂度无疑就是O(n*n)
*/
void dfs(int u, int fa, double dis)
{
if (fa!=-)
for (int i = ; i < st.size(); ++i)
{
int x = st[i];
maxCost[x][u] = maxCost[u][x] = max(maxCost[x][fa], dis);
}
st.push_back(u);
for (int i = ; i < g[u].size(); ++i)
{
int v = g[u][i].to;
if (v == fa) continue;
dfs(v, u, g[u][i].dist);
}
}
int main()
{
int t, n, cnt;
double B;
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
cnt = ;
st.clear();
for (int i = ; i < n; ++i)
{
father[i] = i;
g[i].clear();
scanf("%d%d%d", &x[i], &y[i], &p[i]);
}
for (int i = ; i < n; ++i)
{
for (int j = i + ; j < n; ++j)
{
p2[i][j] = p2[j][i] = p[i] + p[j];
//边集数组
a[cnt].form = i;
a[cnt].to = j;
a[cnt].p = p[i] + p[j];
a[cnt++].dist = sqrt((x[i] - x[j])*(x[i] - x[j]) + (y[i] - y[j])*(y[i] - y[j]));
}
}
sort(a, a + cnt);
B = kruskal(cnt);
dfs(, -, );
double ans = ; //枚举在哪两个之间建免费的道路
for (int i = ; i < n; ++i)
for (int j = i + ; j < n; ++j)
ans = max(ans, p2[i][j] / (B - maxCost[i][j]));
printf("%.2lf\n", ans);
}
return ;
}

uvaLive5713 次小生成树的更多相关文章

  1. UVALive-5713 Qin Shi Huang's National Road System (次小生成树)

    题目大意:有n个城市,要修一些路使得任意两个城市都能连通.但是有人答应可以不计成本的帮你修一条路,为了使成本最低,你要慎重选择修哪一条路.假设其余的道路长度为B,那条别人帮忙修的道路两端城市中的总人口 ...

  2. HDU 4081Qin Shi Huang's National Road System(次小生成树)

    题目大意: 有n个城市,秦始皇要修用n-1条路把它们连起来,要求从任一点出发,都可以到达其它的任意点.秦始皇希望这所有n-1条路长度之和最短.然后徐福突然有冒出来,说是他有魔法,可以不用人力.财力就变 ...

  3. POJ1679 The Unique MST[次小生成树]

    The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 28673   Accepted: 10239 ...

  4. The Unique MST(次小生成树)

    Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 22335   Accepted: 7922 Description Give ...

  5. URAL 1416 Confidential --最小生成树与次小生成树

    题意:求一幅无向图的最小生成树与最小生成树,不存在输出-1 解法:用Kruskal求最小生成树,标记用过的边.求次小生成树时,依次枚举用过的边,将其去除后再求最小生成树,得出所有情况下的最小的生成树就 ...

  6. POJ1679The Unique MST(次小生成树)

    The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 25203   Accepted: 8995 D ...

  7. [kuangbin带你飞]专题八 生成树 - 次小生成树部分

    百度了好多自学到了次小生成树 理解后其实也很简单 求最小生成树的办法目前遇到了两种 1 prim 记录下两点之间连线中的最长段 F[i][k] 之后枚举两点 若两点之间存在没有在最小生成树中的边 那么 ...

  8. URAL 1416 Confidential(次小生成树)

    题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1416 Zaphod Beeblebrox — President of the Impe ...

  9. ACM题目————次小生成树

    Description 最小生成树大家都已经很了解,次小生成树就是图中构成的树的权值和第二小的树,此值也可能等于最小生成树的权值和,你的任务就是设计一个算法计算图的最小生成树. Input 存在多组数 ...

随机推荐

  1. 《学习opencv》笔记——矩阵和图像处理——cvMinManLoc,cvMul,cvNot,cvNorm and cvNormalize

    矩阵和图像的操作 (1)cvMinManLoc函数 其结构 void cvMinMaxLoc(//取出矩阵中最大最小值 const CvArr* arr,//目标矩阵 double* min_val, ...

  2. Linux编程实现守护进程

    Linux 守护程序 守护进程(Daemon)它是在一个特定的过程的背景进行.它独立于控制终端的和周期性地执行某些任务或待某些事件.是一种非常实用的进程. Linux的大多数server就是用守护进程 ...

  3. 纯后端尝试写一个前端slide插件

    概述 由于项目组前端人员缺失,又赶上需要在手机端做一个slide效果的页面,所以只能自己硬着头皮上了,写的很简单,请大家不要笑话,只是拿出来分享下,大家先看下完成后的效果,如下: 过程 看了效果图是不 ...

  4. VC/MFC 工具栏上动态添加组合框等控件的方法

    引言 工具条作为大多数标准的Windows应用程序的一个重要组成部分,使其成为促进人机界面友好的一个重要工具.通过工具条极大方便了用户对程序的操作,但是在由Microsoft Visual C++开发 ...

  5. 一句话解释JVM中空间分配担保的问题

    先解释YGC: 当对象生成在EDEN区失败时,出发一次YGC,先扫描EDEN区中的存活对象,进入S0区,S0放不下的进入OLD区,再扫描S1区,若存活次数超过阀值则进入OLD区,其它进入S0区,然后S ...

  6. leetCode 34.Search for a Range (搜索范围) 解题思路和方法

    Search for a Range Given a sorted array of integers, find the starting and ending position of a give ...

  7. CSS——inline-block属性

    Inline-block 是元素 display属性的一个值 .这个名字的由来是因为,可以简单的解释为inline+block :display设置这个值的元素,兼具行内元素( inline elem ...

  8. 60s 经济学探奇

    理解经济学 什么是经济学.对于学习金融的同学,一定会给你搬出一大堆定义.例证.学派.说经济学是一门研究研究价值的生产.流通.分配.消费的规律的理论. 非常高大上的感觉,可是对于我这样没有什么金融学理论 ...

  9. Access Violation at address 00000000.Read of address 00000000 解决办法

    是数组越标或没有初始化某个对象之类的问题,搂住细细检查一下代码, 使用指针前未做检查,而这个指针未初始化. 可能是new后没有delete,这样出现溢出的可能性比较大     检查代码或者跟踪试试 使 ...

  10. listview改变选中行字体颜色

    [android]listview改变选中行字体颜色 目标:选中item,其字体设置为#3197FF,未选中的,其字体为#FFFFFF 与listvew设置选中行item背景图片一样,使用select ...