HDU-4081 Qin Shi Huang's National Road System(最小生成树[Prim])

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.
HDU-4081 Qin Shi Huang's National Road System(最小生成树[Prim])_第1张图片
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

65.00
70.00

题目給的稠密图,怕超时只得放弃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;
}


你可能感兴趣的:(最小生成树,图论,HDU,Prim)