标签: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