HDU 4081 Qin Shi Huang's National Road System

来源:互联网 发布:nginx宕机原因 编辑:程序博客网 时间:2024/06/06 13:23

传送门

这个题也是类似求比值最优的问题,应该不能简单贪心求解,就只好枚举喽。
A是某条边上两点的点权之和,B是在上述两点已经连通的情况下图的最小生成树的值。想让A/B最大。
枚举每条边,也就枚举了每种可能的A,有两种情况:
- 该边 是 mst上的边,在这两点已经确定的情况下,B的最小值就是mst的值减去该边的权值。(借助kruskal算法可以理解)
- 该边 不是 mst上的边,此时mst加上该边一定会形成有且只有一个环,环上除此边以外任意一条边的权值只会小于等于该边的权值,而且环上去除任意一条边之后就是生成树。所以在这种情况下,B的最小值就是mst的值减去该环上属于mst的边(除此边之外)中的最大权值。
可以设这条不在mst中的边的起点和终点为i,j,那么只要求出在mst中ij路径上(有且只有一条路径)的最大边权max_edge[i][j]就可以了。用prim顺便求这个会比较方便。(在松弛循环中可以根据前驱来更新,且prim要确定入选mst边时也会根据前驱)
求“次小生成树”也会用到max_edge[i][j]

#include <iostream>#include <algorithm>#include <vector>#include <cstring>#include <cmath>using namespace std;const int INF = 1e9;const int MAXN = 1e3 + 2;int N;struct Point{    int x, y, pop;}city[MAXN];double g[MAXN][MAXN];bool active[MAXN][MAXN];double max_edge[MAXN][MAXN];bool vis[MAXN];double d[MAXN];int pre[MAXN];double ans;double B;void init(){    fill(vis, vis + N, 0);    fill(d, d + N, INF);    memset(active, 0, sizeof active);    ans = -1;}double getDistance(int i, int j){    return sqrt((double)(pow(city[i].x - city[j].x, 2) + pow(city[i].y - city[j].y, 2)));}void prim(){    B = 0;    d[0] = 0;    for (int i = 0; i < N; i++)    {        double mind = INF;        int u = -1;        for (int j = 0; j < N; j++)        {            if (!vis[j] && d[j] < mind)            {                mind = d[j];                u = j;            }        }        B += mind;        vis[u] = 1;        if (u) active[u][pre[u]] = active[pre[u]][u] = 1;        for (int j = 0; j < N; j++)        {            if (vis[j] && j != u)       ////            {                if (pre[u] == j) max_edge[u][j] = max_edge[j][u] = g[u][j];                else max_edge[u][j] = max_edge[j][u] = max(max_edge[pre[u]][j], g[u][pre[u]]);            }            else if (!vis[j] && g[u][j] < d[j])            {                d[j] = g[u][j];                pre[j] = u;            }        }    }}int main(){    int T;    scanf("%d", &T);    for (; T--;)    {        scanf("%d", &N);        init();        for (int i = 0; i < N; i++)            scanf("%d%d%d", &city[i].x, &city[i].y, &city[i].pop);        for (int i = 0; i < N; i++)            for (int j = 0; j < N; j++)                if (i != j) g[i][j] = g[j][i] = getDistance(i, j);        prim();   // 其重要任务是计算数组max_edge[][]        for (int i = 0; i < N; i++)        {            for (int j = 0; j < N; j++)            {                if (i != j)                {                    if (active[i][j])                        ans = max(ans, ((double)(city[i].pop + city[j].pop)) / (B - g[i][j]));                    else ans = max(ans, ((double)(city[i].pop + city[j].pop)) / (B - max_edge[i][j]));                }            }        }        printf("%.2f\n", ans);    }    return 0;}
0 0
原创粉丝点击