题目请戳这里
题目大意:秦始皇要修路,有n个城市,给定城市坐标和人数,修一条路要花钱和劳动力,劳动力就是这条路连接2个城市的人口和。秦始皇要修n-1条路,要使总长度最小。徐福说他有法术能修一条路不需要任何代价和劳动力。不过秦始皇想用这条路代替某条路使总路程最小,徐福想用这条路使劳动力最小,最后一折衷求一个A/B,A值这条特殊路的劳动力,B指其他n-2条路长度。
题目分析:如果没有这条特殊路捣乱的话就是红果果的最小生成树了,所以先求一颗最小生成树,求出总权值B,并且标记在生成树上的边。最后枚举每一条边,边分2种:
1。边<i,j>在最小生成树上,那么A=city[i].p + city[j].p,B = B - dis[i][j];
2。边不<i,j>在最小生成树上,那么A = city[i].p+city[j].p,B = B - path[i][j];
第一种就不说了,关键是第二种,如果枚举的边不在最小生成树上,那么加入这条边原来的生成树必形成一个环,因为要使总路程最小,所以必须删掉这个环上最大的边,这个环上最大的边就是原生成树上i->j的最大边,在求最小生成树的时候可以顺便求出。在用prim算法不断加点的时候,假设T是已经在生成树上的点,v是要加入的,那么T中所有点到v路径上的最大值就是T中所有点到v的前驱节点的最大值和v点到T集合距离的最小值的最大值。
详情请见代码:
#include <iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> #include<cctype> #include<map> #include<vector> #include<set> #include<queue> #include<string> using namespace std; const int N = 1005; const int M = 500005; const int INF = 0x3f3f3f3f; const double eps = 1e-6; const double PI = acos(-1.0); typedef __int64 ll; double dis[N][N]; double path[N][N]; bool used[N][N]; bool flag[N]; double lowcost[N]; int pre[N]; struct node { int x,y,p; }city[N]; int n; double B; double getdis(int x1,int y1,int x2,int y2) { return sqrt((double)(x1 - x2) * (double)(x1 - x2) + (double)(y1 - y2) * (double)(y1 - y2)); } void prim() { B = 0; int i,j; memset(flag,false,sizeof(flag)); memset(path,0,sizeof(path)); for(i = 1;i <= n;i ++) { lowcost[i] = dis[1][i]; pre[i] = 1; } flag[1] = true; for(i = 1;i < n;i ++) { double Min = 100000000.0; int v; for(j = 1;j <= n;j ++) { if(flag[j] == false && lowcost[j] < Min) { Min = lowcost[j]; v = j; } } B += Min; used[pre[v]][v] = used[v][pre[v]] = true; for(j = 1;j <= n;j ++) { if(flag[j] == true) { path[j][v] = path[v][j] = max(lowcost[v],path[j][pre[v]]); } } flag[v] = true; for(j = 1;j <= n;j ++) { if(flag[j] == false && lowcost[j] > dis[v][j]) { lowcost[j] = dis[v][j]; pre[j] = v; } } } } int main() { int t,i,j; scanf("%d",&t); while(t --) { scanf("%d",&n); for(i = 1;i <= n;i ++) scanf("%d%d%d",&city[i].x,&city[i].y,&city[i].p); for(i = 1;i <= n;i ++) for(j = 1;j <= i;j ++) { if(i == j) dis[i][j] = 0; else dis[i][j] = dis[j][i] = getdis(city[i].x,city[i].y,city[j].x,city[j].y); } memset(used,false,sizeof(used)); prim(); double ans = 0.0; for(i = 1;i <= n;i ++) { for(j = 1;j < i;j ++) { if(used[i][j]) ans = max(ans,(double)(city[i].p + city[j].p)/(B - dis[i][j])); else ans = max(ans,(double)(city[i].p + city[j].p)/(B - path[i][j])); } } printf("%.2lf\n",ans); } return 0; } //156MS 16896K