Save your cats Aizu
阿新 • • 發佈:2018-12-14
題意:
給出一個圖,這個圖形封閉區域(可能多個可能一個也沒有),問最少需要破壞多少邊使得封閉區域不封閉。先給出每個點的座標,然後給出每條邊的關係。
題解:
這個題因為封閉區域可能一個可能多個可能沒有,所以正向思維去做這個題會比較複雜,把一些邊破壞掉之後,得到的圖不在存在封閉區域,那麼破壞邊之後得到的圖就是一棵樹,所以,總的邊長度之和=要破壞的長度 + 破壞完後剩下的樹的邊的總長度,既然希望破壞的長度儘可能的小, 只需要讓得到的樹儘可能的大就可以了,這樣問題就轉化成了求一棵最大生成樹,用並查集來做,這樣這個問題就很簡單了。
附上程式碼:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; const int N=11000; struct node{ double x,y; }; node point[N]; double dist(node a,node b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } struct edge{ int u,v; double d; }; edge edges[N*(N+1)/2+5]; bool cmp(edge a,edge b) { return a.d>b.d; } int n,m; int pre[N]; int find(int x) { if(x==pre[x]){ return x; }else{ pre[x]=find(pre[x]); return pre[x]; } } void merge(int u,int v) { int t1=find(u); int t2=find(v); if(t1!=t2){ pre[t2]=t1; } return ; } int main() { while(scanf("%d%d",&n,&m)!=EOF){ for(int i=1;i<=n;i++){ pre[i]=i; } for(int i=1;i<=n;i++){ scanf("%lf%lf",&point[i].x,&point[i].y); } double sum=0; int temp1,temp2; for(int i=0;i<m;i++){ scanf("%d%d",&temp1,&temp2); edges[i].u=temp1; edges[i].v=temp2; edges[i].d=dist(point[temp1],point[temp2]); sum=sum+edges[i].d; } sort(edges,edges+m,cmp); double s=0; for(int i=0;i<m;i++){ int x=find(edges[i].u); int y=find(edges[i].v); if(x!=y){ merge(x,y); s=s+edges[i].d; } } double ans=0; ans=sum-s; printf("%.3f\n",ans); } return 0; }