标签:hdu4081
2 4 1 1 20 1 2 30 200 2 80 200 1 100 3 1 1 20 1 2 30 2 2 40
65.00 70.00
题意:给定n个点的点权及相互间的边权,求一棵树,其中一条边的边权变为0,树的比率值为该0值边所连的两点的点权和/剩下的树边和,求这个值最大是多少。
题解:这题要用到次小生成树的思想,即找到最小生成树,然后添加一条边构成环,再删掉环中属于最小树的最大边,用这种方法遍历所有边以找到最终ans。
#include <stdio.h> #include <string.h> #include <math.h> #include <algorithm> #define maxn 1002 #define maxm (maxn * maxn) >> 1 using std::sort; struct Node{ int u, v; double dist; } E[maxm]; //存储边 struct Node2{ int x, y, peo; } V[maxn]; //存储顶点 int head[maxn], end[maxn]; //存储集合首尾 struct Node3{ int u, next; } G[maxn]; //链式前向星存集合归属信息 int pre[maxn]; //并查集 double max[maxn][maxn]; //存储最小树上的两点间最长的一条单元路 double maxv(double a, double b){ return a > b ? a : b; } double calDist(int i, int j) { double x = V[i].x - V[j].x; double y = V[i].y - V[j].y; return sqrt(x * x + y * y); } bool cmp(Node a, Node b){ return a.dist < b.dist; } int ufind(int k) { int a = k, b; while(pre[k] != -1) k = pre[k]; while(a != k){ b = pre[a]; pre[a] = k; a = b; } return k; } double Kruskal(int n, int m) { memset(pre, -1, sizeof(pre)); int count = n, i, j, k, u, v; double len = 0, dist; for(i = 0; i < n; ++i){ //初始化每个点的集合只有其本身 G[i].u = i; G[i].next = -1; head[i] = end[i] = i; } for(i = 0; i < m; ++i){ u = E[i].u; v = E[i].v; dist = E[i].dist; u = ufind(u); v = ufind(v); if(u != v){ for(j = head[u]; j != -1; j = G[j].next) for(k = head[v]; k != -1; k = G[k].next) max[G[j].u][G[k].u] = max[G[k].u][G[j].u] = dist; //合并集合 G[end[v]].next = head[u]; head[u] = head[v]; pre[v] = u; --count; len += dist; if(1 == count) break; //最小树生成 } } return len; } int main() { //freopen("stdin.txt", "r", stdin); int t, n, i, j, id; double minLen, ans; scanf("%d", &t); while(t--){ scanf("%d", &n); for(i = 0; i < n; ++i) scanf("%d%d%d", &V[i].x, &V[i].y, &V[i].peo); for(i = id = 0; i < n; ++i) for(j = i + 1; j < n; ++j){ E[id].u = i; E[id].v = j; E[id++].dist = calDist(i, j); } sort(E, E + id, cmp); minLen = Kruskal(n, id); ans = 0; for(i = 0; i < n; ++i) //枚举所有魔法边 for(j = i + 1; j < n; ++j){ ans = maxv(ans, (V[i].peo + V[j].peo) / (minLen - max[i][j])); } printf("%.2lf\n", ans); } return 0; }
附之前写的一个用prim的超时代码:
#include <stdio.h> #include <string.h> #include <math.h> #include <limits.h> #define maxn 1002 double map[maxn][maxn], max[maxn][maxn]; bool vis[maxn]; struct Node{ int x, y, peo; } node[maxn]; double calDist(int i, int j) { int x = node[i].x - node[j].x; int y = node[i].y - node[j].y; return sqrt((double)(x * x + y * y)); } double prim(int n) { memset(vis, 0, sizeof(vis)); int count = 0, i, j, v; double tmp, len = 0; vis[0] = 1; while(count < n - 1){ for(i = 0, tmp = INT_MAX; i < n; ++i){ if(!vis[i]) continue; for(j = 0; j < n; ++j){ if(vis[j]) continue; if(map[i][j] < tmp){ tmp = map[i][j]; v = j; } } } for(i = 0; i < n; ++i) if(vis[i]) max[i][v] = max[v][i] = tmp; ++count; vis[v] = 1; len += tmp; } return len; } double getAns(int n, double minLen) { int i, j, peo; double ans = 0, tmp; for(i = 0; i < n; ++i) for(j = i + 1; j < n; ++j){ tmp = (node[i].peo + node[j].peo) / (minLen - max[i][j]); if(tmp > ans) ans = tmp; } return ans; } int main() { int t, n, i, j, peo; scanf("%d", &t); while(t--){ scanf("%d", &n); for(i = 0; i < n; ++i) scanf("%d%d%d", &node[i].x, &node[i].y, &node[i].peo); for(i = 0; i < n; ++i) for(j = i + 1; j < n; ++j) map[i][j] = map[j][i] = calDist(i, j); printf("%.2lf\n", getAns(n, prim(n))); } return 0; }
HDU4081 Qin Shi Huang's National Road System 【次小生成树】,布布扣,bubuko.com
HDU4081 Qin Shi Huang's National Road System 【次小生成树】
标签:hdu4081
原文地址:http://blog.csdn.net/chang_mu/article/details/38497083