題目描述
Zjr506很喜歡貓,某一天他突然心血來潮,想捕捉學校裏活動的貓。
爲了捕貓,Zjr506在校園中放置了N個木樁,當他見到有貓進入他的狩獵範圍後,就會以迅雷不及掩耳的速度在一些木樁之間繞上藩籬以困住這些貓。
一段時間後,Zjr506在繞了M個藩籬後興高采烈的離開了。作爲正義的使者,Ztxz16不忍心看到這些貓受到折磨,於是決定拆除一些藩籬讓所有的貓都逃出去。因爲Zjr506的巧妙設計,藩籬不會在除木樁之外的地方相交。這些藩籬構成了一些封閉的區域,每一個區域中都有一隻貓。
因爲Zjr506製造這些藩籬也不容易,所以Ztxz16希望拆除的藩籬總長度儘量小,現在他希望你告訴他最小的總長度。
數據範圍
N <= 10000, M <= 50000
題目描述是有問題的,有一種特殊情況即一個藩籬經過不止兩個木樁,可以是三個四個,因爲題目僅僅說明藩籬不會在除木樁之外的地方相交。除去這種情況,題解的做法就是對的。
那麼考慮要拆除一些藩籬,使圖中不在任何環,也就是說刪完藩籬後的圖會成爲一棵樹,那麼我們只要做一遍最大生成樹即可。
代碼
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=10000+5;const int maxm=50000+5;
int i,j,f[maxn],n,m;
double sum;
struct ar{
int x,y;double d;
}b[maxm],z[maxn];
bool cmp(ar x,ar y){
return x.d>y.d;
}
double sqr(int x){
double a=x;
return a*a;
}
int get(int x){
if (f[x]==0) return x;
return f[x]=get(f[x]);
}
int main(){
scanf("%d%d",&n,&m);
fo(i,1,n) scanf("%d%d",&z[i].x,&z[i].y);
fo(i,1,m){
scanf("%d%d",&b[i].x,&b[i].y);
int x=b[i].x,y=b[i].y;
b[i].d=sqr(z[x].x-z[y].x)+sqr(z[x].y-z[y].y);
b[i].d=sqrt(b[i].d);
sum+=b[i].d;
}
sort(b+1,b+1+m,cmp);
fo(i,1,m){
int x=b[i].x,y=b[i].y;
x=get(x),y=get(y);
if (x!=y){
sum-=b[i].d;
f[x]=y;
}
}
printf("%.5lf\n",sum);
}