2011年 北京区域赛A题 Qin Shi Huang's National Road System // hdu 4081 Qin Shi Huang's National Road System 最优比率生成树
/* 2011年北京区域赛A题 Qin Shi Huang's National Road System 题目: 秦始皇想要修公路,使得这n座城市可以互达,题目给出n所城市的二维坐标以及每座城 市的价值,现在有人可以免费帮助秦始皇修理任意一条公路,现在要想使得比率A/B最大, A表示这条公路所在的两座城市的价值,B表示所有的公路长度(不包括这条公路的长度)。 分析: 想要比率最大,所以A要尽可能大,B尽可能小。要使B尽可能小的话,可以先求的最小生 成树,然后枚举在最小生成树上的每条边,删除该边后得到的两个点集中分别找到最大价值 的点(城市),然后更新答案。时间复杂度为O(n^2)。而找两个集合中的点时,我们可以 通过dfs求得,具体实现请看代码 */ #include <cstdio> #include <cstring> #include <iostream> #include <cmath> using namespace std; const int X = 1002; #define INF 1e12 struct node { int x,y,w; }p[X]; int n; double map[X][X]; double dis[X],total,ans; bool use[X]; int pre[X]; //记录点i的前趋节点 double dist(int x1,int y1,int x2,int y2) //距离 { return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } void prim() //求最小生成树 { memset(pre,0,sizeof(pre)); total = 0; memset(use,false,sizeof(use)); for(int i=1;i<=n;i++) dis[i] = INF; dis[1] = 0; int k; double MIN; for(int i=0;i<n;i++) { MIN = INF; for(int j=1;j<=n;j++) if(!use[j]&&dis[j]<MIN) MIN = dis[k = j]; use[k] = true; total += MIN; for(int j=1;j<=n;j++) if(!use[j]&&dis[j]>map[k][j]) dis[j] = map[k][j],pre[j] = k; } } void dfs(int i) //dfs,通过对他的后趋点进行深搜,找到同一集合中所有的点 { use[i] = true; for(int j=1;j<=n;j++) if(!use[j]&&pre[j]==i) dfs(j); } void solve() { double temp; ans = 0; int a,b; for(int i=1;i<=n;i++) //枚举每条边 { if(pre[i]==0) continue; temp = total-map[i][pre[i]]; //删除边i,pre[i] memset(use,false,sizeof(use)); dfs(i); a = b = 0; for(int j=1;j<=n;j++) { if(use[j]&&j!=pre[i]) //与pre[i]同一集合中的点,找到最大的价值城市 a = max(a,p[j].w); else if(!use[j]&&j!=i) //与i同一集合中的点。。。 b = max(b,p[j].w); } ans = max(ans,(a+b)/temp); } printf("%.2lf\n",ans); } int main() { freopen("sum.in","r",stdin); freopen("sum.out","w",stdout); int t; cin>>t; while(t--) { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].w); for(int j=i;j>=1;j--) //预处理出所有点与点之间的距离 map[i][j] = map[j][i] = dist(p[i].x,p[i].y,p[j].x,p[j].y); } prim(); solve(); } return 0; }