Qin Shi Huang's National Road System
题目链接:Click Here~
题目重述:
题目说秦始皇要修路,把N个城市用N-1条边连通。且他希望花费最小,但是这时候有一个多管闲事的道士出来说他有魔法可以帮助秦始皇变成一条路,但是只能变出一条。但是,两个人对修路的法案存在歧义,道士希望修路可以给更多的百姓带来福利,而秦始皇希望修路要尽量使花费小。最后,秦始皇拿出了一个公式A/B,A表示两个城市的人数,B表示出了用魔法变出来的路外,最短的总距离。现在要你求出A/B的最大值。
思路分析:
从题目可以看出是一个此小生成树问题,但是也有人有DP AC了。具体思路就看网上别人的解释吧。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int N = 1e3 + 5;
int n,m;
double path[N][N],G[N][N];
bool used[N][N],hash[N];
struct Point
{
double x,y,cost;
}p[N];
double Dist(Point a,Point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double Prim()
{
int pre[N];
double sum = 0,mincost[N];
memset(hash,0,sizeof(hash));
memset(used,0,sizeof(used));
memset(path,0,sizeof(path));
hash[1] = 1;
for(int i = 1;i <= n;++i){
mincost[i] = G[1][i];
pre[i] = 1;
}
for(int i = 1;i < n;++i)
{
int u = -1;
for(int j = 1;j <= n;++j)if(!hash[j]){
if(u == -1||mincost[j] < mincost[u])
u = j;
}
hash[u] = 1;
used[u][pre[u]] = used[pre[u]][u] = 1; //判断两点之间是否在生成树中
sum += G[pre[u]][u];
for(int j = 1;j <= n;++j)
{
if(hash[j]&&u != j){
path[j][u] = path[u][j] = max(mincost[u],path[j][pre[u]]); //生成树中的最大权值
// path[j][u] = path[u][j] = mincost[u];
}
if(!hash[j]){
if(mincost[j] > G[u][j]){
mincost[j] = G[u][j];
pre[j] = u;
}
}
}
}
return sum;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i = 1;i <= n;++i){
scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].cost);
}
memset(G,0,sizeof(G));
for(int i = 1;i <= n;++i)
for(int j = i+1;j <= n;++j){
G[i][j] = G[j][i] = Dist(p[i],p[j]);
}
double mincost = Prim();
double ratio = -1;
for(int i = 1;i <= n;++i)
for(int j = 1;j <= n;++j)
printf("path[%d][%d] = %lf\n",i,j,path[i][j]);
for(int i = 1;i <= n;++i)
for(int j = i+1;j <= n;++j){
if(used[i][j]){
ratio = max(ratio,(p[i].cost+p[j].cost)/(mincost-G[i][j]));
}else
{ //删除生成树中的最大的一条边,生成一个类此小生成树(因为,不是严格的此小生成树)
ratio = max(ratio,(p[i].cost+p[j].cost)/(mincost-path[i][j]));
}
}
printf("%.2lf\n",ratio);
}
return 0;
}