Qin Shi Huang's National Road SystemTime Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 6631 Accepted Submission(s): 2335
Problem Description
During the Warring States Period of ancient China(476 BC to 221 BC), there were seven kingdoms in China ---- they were Qi, Chu, Yan, Han, Zhao, Wei and Qin. Ying Zheng was the king of the kingdom Qin. Through 9 years of wars, he finally conquered all six other kingdoms and became the first emperor of a unified China in 221 BC. That was Qin dynasty ---- the first imperial dynasty of China(not to be confused with the Qing Dynasty, the last dynasty of China). So Ying Zheng named himself "Qin Shi Huang" because "Shi Huang" means "the first emperor" in Chinese.
Qin Shi Huang undertook gigantic projects, including the first version of the Great Wall of China, the now famous city-sized mausoleum guarded by a life-sized Terracotta Army, and a massive national road system. There is a story about the road system: There were n cities in China and Qin Shi Huang wanted them all be connected by n-1 roads, in order that he could go to every city from the capital city Xianyang. Although Qin Shi Huang was a tyrant, he wanted the total length of all roads to be minimum,so that the road system may not cost too many people's life. A daoshi (some kind of monk) named Xu Fu told Qin Shi Huang that he could build a road by magic and that magic road would cost no money and no labor. But Xu Fu could only build ONE magic road for Qin Shi Huang. So Qin Shi Huang had to decide where to build the magic road. Qin Shi Huang wanted the total length of all none magic roads to be as small as possible, but Xu Fu wanted the magic road to benefit as many people as possible ---- So Qin Shi Huang decided that the value of A/B (the ratio of A to B) must be the maximum, which A is the total population of the two cites connected by the magic road, and B is the total length of none magic roads. Would you help Qin Shi Huang? A city can be considered as a point, and a road can be considered as a line segment connecting two points.
Input
The first line contains an integer t meaning that there are t test cases(t <= 10).
For each test case: The first line is an integer n meaning that there are n cities(2 < n <= 1000). Then n lines follow. Each line contains three integers X, Y and P ( 0 <= X, Y <= 1000, 0 < P < 100000). (X, Y) is the coordinate of a city and P is the population of that city. It is guaranteed that each city has a distinct location.
Output
For each test case, print a line indicating the above mentioned maximum ratio A/B. The result should be rounded to 2 digits after decimal point.
Sample Input
Sample Output
Source
Recommend
lcy
|
首先,感谢房神帮我看了一个看了半天没有看出来的错误,定义res时用了int,导致答案错误。
题目大意:给定若干个点及其权值,每条路径的权值为相邻两点权值的和。现要建一棵树,可以免费建一条边,该条边的权值为A,其余的边权 值和为B,问怎样建树可以使得A/B的值最大。
解题思路:先建一个最小生成树,然后枚举每一条边,删除该边后会有两棵树,分别在两棵树中找到权值最大的点计算A,剩余边的权值和为B
这样计算出来的A/B就是最后的答案。所建的树必定和最小生成树只差一条边(想想为什么?)可以用次小生成树去理解。
具体算法:利用kruskal算出权值和,在用邻接表存下这棵树,后用dfs去搜权值最大点。(房神是用并查集存的权值最大点)。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
const int MAX_V = 1005;
const int MAX_E = 500500;
int T, V, E;
int par[MAX_V];
int ran[MAX_V];
vector<int> map[MAX_V];
bool visit[MAX_V];
double cost[MAX_V];
struct vertex {
double x;
double y;
};
vertex ve[MAX_V];
void init(int n) {
for(int i = 0; i < n; ++i) {
par[i] = i;
ran[i] = 0;
}
}
int fin(int x) {
if(par[x] == x) {
return x;
} else {
return par[x] = fin(par[x]);
}
}
bool same(int x, int y) {
return fin(x) == fin(y);
}
void unite(int x, int y) {
x = fin(x);
y = fin(y);
if(x == y) return ;
if(ran[x] < ran[y]) {
par[x] = y;
} else {
par[y] = x;
if(ran[x] == ran[y]) ran[x]++;
}
}
struct edge {
int u, v;
double cost;
};
bool comp(const edge & e1, const edge & e2) {
return e1.cost < e2.cost;
}
edge es[MAX_E];
edge es2[MAX_V];
double kruskal() {
sort(es, es + E, comp);
init(V);
double res = 0;
int p = 0;
for(int i = 0; i < E; ++i) {
edge e = es[i];
if(!same(e.u, e.v)) {
unite(e.u, e.v);
res += e.cost;
es2[p++] = e;
map[e.u].push_back(e.v); //存最小生成树
map[e.v].push_back(e.u);
}
}
return res;
}
double dfs(int v, double ans) { //搜索权值最大点
visit[v] = true;
ans = max(ans, cost[v]);
for(unsigned int i = 0; i < map[v].size(); ++i) {
if(!visit[map[v][i]]) {
ans = max(dfs(map[v][i], ans), cost[map[v][i]]);
}
}
return ans;
}
int main()
{
int T;
scanf("%d", &T);
while(T--) {
E = 0;
scanf("%d", &V);
for(int i = 0; i < V; ++i) {
map[i].clear();
scanf("%lf%lf%lf", &ve[i].x, &ve[i].y, &cost[i]);
}
for(int i = 0; i < V; ++i) { //计算所有边
for(int j = i + 1; j < V; ++j) {
es[E].u = i;
es[E].v = j;
es[E].cost = sqrt((ve[i].x - ve[j].x) * (ve[i].x - ve[j].x) + (ve[i].y - ve[j].y) * (ve[i].y - ve[j].y));
E++;
}
}
double A = 0, B = 0;
B = kruskal();
double ans = 0;
for(int i = 0; i < V - 1; ++i) {
for(int j = 0; j < V; ++j) {
visit[j] = false; //点是否访问过
}
visit[es2[i].u] = true;
visit[es2[i].v] = true;
A = dfs(es2[i].v, 0) + dfs(es2[i].u, 0); //两次搜索不会有影响
B -= es2[i].cost; //删除该边
ans = max(ans, A / B);
B += es2[i].cost; //加上该边
}
printf("%.2lf\n", ans);
}
return 0;
}