题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4081
题目大意:
求一个图的生成树,
可以指定一条边为“魔法边”,使其边权变为0。
在此基础上,要求 “ '魔法边' 连接的两点的点权 / 生成树上其它边的边权" 最大。
算法:
首先,一定是在最小生成树上去掉一条边,然后在被分成的两部分间加上一条边。
因为把最小生成树去掉一条边的话,残留在两部分的生成树就是它们各自的最小生成树,否则把这条边加回来完全可以构成一个更优的最小生成树,矛盾。
然后我们枚举最小生成树上去掉的是哪条边,此时“生成树上其它边的边权",已经被确定。那么我们就直接在被分割出的两部分中各找一个点权最大的点连”魔法边“即可。
PS:1000个点的完全图跑krustal还是比较困难的,我写的prim。
代码如下:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cstdlib>
#include <ctime>
#include <climits>
#include <cmath>
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <stack>
#include <deque>
#include <algorithm>
#define inf 0x3f3f3f3f
#define mp make_pair
#define fi first
#define nd second
using namespace std;
const int MAXN = 1100;
int x[MAXN], y[MAXN], z[MAXN];
int m1[MAXN], m2[MAXN];
bool vis[MAXN];
vector <pair <int, pair <int, int> > > edge;
vector <pair <int, int> > nedge;
queue <int> q;
vector <int> mm[MAXN];
priority_queue <pair <double, pair <int, int> > > pq;
int n;
double dis(int i, int j)
{
return sqrt((double)(x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
}
int bfs(int s, int t)
{
memset(vis, 0, sizeof(vis));
vis[s] = true;
while(! q.empty())
{
q.pop();
}
vis[s] = true;
q.push(s);
int tmp = 0;
while(!q.empty())
{
int x = q.front();
q.pop();
tmp = max(tmp, z[x]);
for(int i = 0; i < mm[x].size(); i ++)
{
if(mm[x][i] == t)
{
continue;
}
if(vis[mm[x][i]])
{
continue;
}
q.push(mm[x][i]);
vis[mm[x][i]] = true;
}
}
return tmp;
}
int main()
{
int cas;
scanf("%d", &cas);
while(cas --)
{
scanf("%d", &n);
for(int i = 0; i < n; i ++)
{
scanf("%d %d %d", &x[i], &y[i], &z[i]);
mm[i].clear();
}
memset(m1, -1, sizeof(m1));
memset(m2, -1, sizeof(m2));
memset(vis, 0, sizeof(vis));
edge.clear();
nedge.clear();
while(! pq.empty())
{
pq.pop();
}
for(int i = 1; i < n; i ++)
{
pq.push(mp(-dis(i, 0), mp(i, 0)));
}
vis[0] = true;
double sum = 0.0;
while(! pq.empty())
{
int y = - pq.top().fi;
int x = pq.top().nd.fi;
int p = pq.top().nd.nd;
pq.pop();
if(vis[x])
{
continue;
}
vis[x] = true;
mm[x].push_back(p);
mm[p].push_back(x);
nedge.push_back(mp(p, x));
sum += dis(x, p);
for(int i = 0; i < n; i ++)
{
if(!vis[i])
{
pq.push(mp(-dis(i, x), mp(i, x)));
}
}
}
double ans = 0;
for(int filter = 0; filter < nedge.size(); filter ++)
{
int i = nedge[filter].fi;
int j = nedge[filter].nd;
int a = bfs(i, j);
int b = bfs(j, i);
ans = max(ans, (a + b) / (sum - dis(i, j)));
}
printf("%.2lf\n", ans);
}
return 0;
}