Qin Shi Huang's National Road System
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)
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
2
4
1 1 20
1 2 30
200 2 80
200 1 100
3
1 1 20
1 2 30
2 2 40
Sample Output
题目給的稠密图,怕超时只得放弃Kruskal算法。
第一反应是贪心,直接在人口最多的两座城市建立magic rode,仔细一想明显会错,A虽然取得最大,但是B也可能会大。
然后就想到枚举任意两点的边为magic rode,求最小生成树,但这样又会超时。
最后看到大家都是先求最小生成树,再枚举每条边去掉,然后在两部分分别找人口最大的城市添上magic rode即可
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
struct Edge {
int s,e;
double d;
}tr[1005];//tr[i]表示第i次加入最小生成树的边
const double INF=99999999;
const double EPS=0.000001;
int n,x[1005],y[1005],p[1005],near[1005],u,maxp;
double g[1005][1005],dis[1005],tmp,ans,sum;
bool vis[1005];
vector<int> adj[1005];//adj[i]表示最小生成树中与i有边的点集
void Prim() {
int i,j;
dis[0]=INF,dis[1]=sum=0;
near[1]=1;//near[i]表示i点距离最小生成树的near[i]点最近
for(i=0;i<n;++i) {
u=0;
for(j=1;j<=n;++j)
if(!vis[j]&&dis[j]+EPS<dis[u])
u=j;
vis[u]=true;
sum+=(tr[i].d=dis[u]);
adj[tr[i].s=u].push_back(near[u]);
adj[tr[i].e=near[u]].push_back(u);
for(j=1;j<=n;++j) {
if(dis[j]-EPS>g[u][j]) {
dis[j]=g[u][j];
near[j]=u;
}
}
}
}
void dfs(int s) {//深搜所有在s这边的点
vis[s]=true;
maxp=max(maxp,p[s]);
for(int i=0;i<adj[s].size();++i)
if(!vis[adj[s][i]])
dfs(adj[s][i]);
}
int main() {
int i,j,T,dx,dy;
scanf("%d",&T);
while(T--) {
scanf("%d",&n);
for(i=1;i<=n;++i) {
scanf("%d%d%d",x+i,y+i,p+i);
for(j=1;j<i;++j) {
dx=x[i]-x[j],dy=y[i]-y[j];
g[i][j]=g[j][i]=sqrt(double(dx*dx+dy*dy));
}
vis[i]=false,dis[i]=INF;
adj[i].clear();
}
adj[0].clear();
Prim();
ans=0;
for(i=1;i<n;++i) {
tmp=maxp=0;
memset(vis,false,sizeof(vis));
vis[tr[i].s]=true;//将tr[i].e到tr[i].s这条边删除
dfs(tr[i].e);//统计tr[i].e这边所有点最大人口数
tmp+=maxp;
maxp=0;
memset(vis,false,sizeof(vis));
vis[tr[i].e]=true;//将tr[i].s到tr[i].e这条边删除
dfs(tr[i].s);//统计tr[i].s这边所有点最大人口数
tmp+=maxp;
tmp/=(sum-tr[i].d);
if(ans+EPS<tmp)
ans=tmp;
}
printf("%.2lf\n",ans);
}
return 0;
}