题目链接
题目大意:
很多猫被栅栏围了起来,每个栅栏的两端是两个站桩,每组输入有n个站桩和m个栅栏,首先给出每个站桩的坐标,然后给出连接每一个栅栏的两个点,问如何破坏栅栏使消耗最小(即边最小)并且解救出所有被围起来的猫
解题思路:
本题的意思有些难理解,实质是给你一个连通图,图中有一些环,要求去掉一些边,使得该图不再有环。
我们的目的是要破坏原本图中的这些环,最大生成树刚好可以满足没有环的条件,去掉剩下的那些边就解决了问题。
AC代码:
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<math.h>
using namespace std;
#define INF 0x3fffffff
#define maxn 10001
int n, m;//顶点个数 边的个数
struct edge {
int u, v;
double w;
}e[50001];
struct node {
int x, y;
}list[maxn];
bool cmp(edge a, edge b) { return a.w > b.w; }
int tree[maxn];
int findroot(int a) {
if (tree[a] == -1)return a;
else {
int tmp = findroot(tree[a]);
tree[a] = tmp;//路径压缩
return tmp;
}
}
double compute(node a, node b) {
return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}
bool hebing(int a, int b) {
a = findroot(a);
b = findroot(b);
if (a != b) {
tree[a] = b;
return true;
}
return false;
}
void init(int x) {
for (int i = 1; i <= x; i++) {
tree[i] = -1;
}
}
int main() {
while (scanf("%d%d", &n, &m) != EOF) {
init(n);
double all = 0;
for (int i = 1; i <= n; i++) {
scanf("%d%d", &list[i].x, &list[i].y);
}
for (int i = 1; i <= m; i++) {
int a, b;
scanf("%d%d", &a, &b);
e[i].u = a; e[i].v = b;
e[i].w = compute(list[a], list[b]);
all += e[i].w;
}
sort(e + 1, e + 1 + m, cmp);
double ans = 0;
for (int i = 1; i <= m; i++) {
if (hebing(e[i].u, e[i].v)) {
ans += e[i].w;
}
}
ans = all - ans;
printf("%.3f\n", ans);
}
return 0;
}