题意
传送门 AOJ 2224
最小生成树算法更改排序条件即得最大生成树算法。求删除部分边以消除所有圈的最小花费,Kruskal 原理是判断加入的 2 个顶点是否在同一个连通分量里,以避免产生圈。这里反过来用即可,边的权值和减去最大生成树即答案。
#include <cstdio>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define abs(x) ((x) < 0 ? -(x) : (x))
#define INF 0x3f3f3f3f
#define delta 0.85
#define eps 1e-3
#define PI 3.14159265358979323846
#define MAX_V 10005
#define MAX_E 10000000
using namespace std;
struct edge{
int u, v;
double cost;
}es[MAX_E];
int V, E;
int X[MAX_V], Y[MAX_V];
bool cmp(const edge& e1, const edge& e2){
return e1.cost > e2.cost;
}
/**** Union_find ****/
int par[MAX_V], rank[MAX_V];
void init_union_find(int n){
for(int i = 0; i < n; i++){
par[i] = i, rank[i] = 0;
}
}
int find(int x){
if(par[x] == x) return x;
return par[x] = find(par[x]);
}
bool same(int x, int y){
return find(x) == find(y);
}
void unite(int x, int y){
x = find(x), y = find(y);
if(x == y) return;
if(rank[x] > rank[y]) par[y] = x;
else{
par[x] = y;
if(rank[x] == rank[y]) ++rank[y];
}
}
/**** Union_find ****/
// Kruskal
double kruskal(){
sort(es, es + E, cmp);
init_union_find(V);
double res = 0;
for(int i = 0; i < E; i++){
edge &e = es[i];
if(!same(e.u, e.v)){
res += e.cost;
unite(e.u, e.v);
}
}
return res;
}
double dist(int u, int v){
double dx = X[u] - X[v], dy = Y[u] - Y[v];
return sqrt(dx * dx + dy * dy);
}
int main(){
while(~scanf("%d%d", &V, &E) && V){
for(int i = 0; i < V; i++) scanf("%d%d", X + i, Y + i);
double sum = 0.0;
for(int i = 0; i < E; i++){
int u, v;
scanf("%d%d", &u, &v);
--u, --v;
es[i].u = u, es[i].v = v, es[i].cost = dist(u, v);
sum += es[i].cost;
}
printf("%.3f\n", sum - kruskal());
}
return 0;
}