#kruskal#[jzoj 2940] 電纜建設

題目

教主上電視了,但是蔚藍城郊區沿河的村莊卻因電纜線路老化而在直播的時候停電,這讓市長SP先生相當的憤怒,他決定重修所有電纜,並改日播放錄像,杜絕此類情況再次發生。
  河流兩旁各有n,m個村莊,每個村莊可以用二維座標表示,其中河流一旁的村莊橫座標均爲x1,河流另一旁的村莊橫座標均爲x2。由於地勢十分開闊,任意兩個村莊可以沿座標系直線修建一條電纜連接,長度即爲兩村莊的距離。要修建若干條電纜,使得任意兩個村莊都可以通過若干個有電纜連接的村莊相連。
  因爲修建的經費與長度成正比,SP市長當然希望所花的錢越少越好,所以他希望你來幫助他設計一套方案,使得電纜總長度最小,並告訴所需要的電纜總長度。


解題思路

同一條直線上的,我們可以相鄰兩兩連邊。
不同的,我們取最近的兩個點進行連邊。
然後跑kruskal最小生成樹就可以了


代碼

#include<cstdio>
#include<algorithm>
#include<cmath>
#define ll long long 
#define rep(i,x,y) for(int i=x;i<=y;i++)
using namespace std; 
int n,m,x1,x2,f[1200005],q[600005],b[600005],tot;
double ans; 
struct node{int x,y; ll z; }a[2400005];
inline ll cf(int x){return 1ll*x*x;}
inline int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
inline bool cmp(node x,node y){return x.z<y.z;}
int main(){
	scanf("%d%d%d%d",&n,&m,&x1,&x2); 
	rep(i,1,n) scanf("%d",&q[i]),q[i]+=q[i-1]; 
	rep(i,1,m) scanf("%d",&b[i]),b[i]+=b[i-1]; 
	int r=1; 	
	rep(i,1,n){
		while(b[r]<q[i]&&r<=m) r++; 
	    a[++tot]=(node){i,n+r,cf(q[i]-b[r])+cf(x2-x1)}; 
		if (r>1) a[++tot]=(node){i,n+r-1,cf(q[i]-b[r-1])+cf(x2-x1)}; 
	}
    rep(i,1,n-1) a[++tot]=(node){i,i+1,cf(q[i]-q[i+1])}; 
    rep(i,1,m-1) a[++tot]=(node){i+n,i+n+1,cf(b[i]-b[i+1])}; 
    rep(i,1,n+m) f[i]=i; 
    sort(a+1,a+tot+1,cmp); 
    int cnt=0;  
    rep(i,1,tot){
    	int x=find(a[i].x),y=find(a[i].y); 
    	if (x!=y){
    		f[x]=y;
			cnt++;  
			ans+=sqrt((double)(a[i].z)); 
    	}
    	if (cnt==(n+m-1)) return 0&printf("%.2lf",ans); 
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章