枚举+最小生成树 hdoj4081 Qin Shi Huang's National Road System

来源:互联网 发布:毕业论文的数据分析 编辑:程序博客网 时间:2024/06/05 13:52

题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4081

题目大意是给你一个图,既有点权又有边权,求一个生成树,你可以任选其中一条边,使它的边权为0,最终使得边权为0的两点的点权和/剩余边的边权和 最小。

我们可以这样思考,从最小生成树中去掉一条边,剩余的两个连通分量用边权为0的边链接。这样是正确的,因为如果你要选择两个点并用0边把它们连接起来,意味着需要在此基础上做一颗最小生成树,求最小生成树的算法是贪心的,因此在此基础上的最小生成树除了0边之外,其他边的集合是原来最小生成树的子集(或者如果存在多棵最小生成树,边权和是相同的)。接下来就是选择0边连接哪两个节点的问题了,显然连接两个点权最大的节点。枚举删去n-1条边,取最大的即是答案。

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#include <vector>using namespace std;const int MAX = 1005;const double INF = 1e10;double map[MAX][MAX], xx[MAX], yy[MAX];int n, p[MAX], vis[MAX], fu, fv, pmax;struct edge {    int u, v;    double w;} dis[MAX], e[MAX];vector<int> ve[MAX];void init(void){    memset(vis, 0, sizeof(vis));    for (int i = 1; i <= n; i ++)        ve[i].clear();    pmax = 0;}inline double dist(double x1, double y1, double x2, double y2){    return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));}int dfs(int x){    vis[x] = 1;    if (p[x] > pmax) pmax = p[x];    for (int i = 0; i < ve[x].size(); i ++) {        if (!vis[ve[x][i]] && !(fu == x && fv == ve[x][i] || fu == ve[x][i] && fv == x)) {            dfs(ve[x][i]);        }    }}double prim(void){    double ret = 0;    vis[1] = 1;    for (int i = 1; i <= n; i ++) {        dis[i].w = map[1][i];        dis[i].u = 1;        dis[i].v = i;    }    for (int i = 1; i <= n - 1; i ++) {        double min = INF;        int minid;        for (int j = 1; j <= n; j ++) {            if (!vis[j] && dis[j].w < min) {                min = dis[j].w;                minid = j;            }        }        vis[minid] = 1;        ret += min;        e[i] = dis[minid];        ve[e[i].u].push_back(e[i].v);        ve[e[i].v].push_back(e[i].u);        for (int j = 1; j <= n; j ++) {            if (!vis[j] && dis[j].w > map[minid][j]) {                dis[j].w = map[minid][j];                dis[j].u = minid;            }        }    }    return ret;}int main(){    int t;    scanf("%d",&t);    while (t --) {        init();        scanf("%d",&n);        for (int i = 1; i <= n; i ++) {            scanf("%lf%lf%d",&xx[i], &yy[i], &p[i]);            for (int j = 1; j < i; j ++) {                map[i][j] = map[j][i] = dist(xx[i], yy[i], xx[j], yy[j]);            }            map[i][i] = INF;        }        double len = prim();        double ans = -INF;        int pp;        for (int i = 1; i <= n - 1; i ++) {            memset(vis, 0, sizeof(vis));            pmax = 0;            fu = e[i].u;            fv = e[i].v;            dfs(fu);            pp = 0;            pp += pmax;            memset(vis, 0, sizeof(vis));            pmax = 0;            dfs(fv);            pp += pmax;            ans = max(ans, pp / (len - e[i].w));        }        printf("%.2lf\n", ans);    }    return 0;}
阅读全文
0 0
原创粉丝点击