P2872

[USACO07DEC]Building Roads S

题意描述

img

输入

4 1
1 1
3 1
2 3
4 3
1 4

输出

4.00

点拨

题目大意就是求最小的能把几个集合连起来的边权值之和,我们考虑建一个最小生成树,树上的边一定会对答案做出贡献,只需要排除已经有的边即可

代码

#include<iostream>
#include<utility>
#include<vector>
#include<cmath>
#include<algorithm>
#include<iomanip>
using namespace std;
typedef long long ll;
#define fi(i,a,b) for(int i = a; i <= b; ++i)
#define fr(i,a,b) for(int i = a; i >= b; --i)
#define x first
#define y second
#define sz(x) ((int)(x).size())
#define pb push_back
using pii = pair<int,int>;
//#define DEBUG
bool vis[1005][1005];
struct point{
    int x,y;
}point[1005];
int f[1005];
struct dis{
    int a,b;
    double w;
    bool operator < (const dis p) const{
        return w < p.w;
    }
};
vector<dis> vec;
int find(int x){
    return f[x] == x ? x:f[x] = find(f[x]);
}
void combin(int x,int y){
    f[find(x)] = find(y);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
#ifdef DEBUG
    //freopen(D:\in.txt,r,stdin);
#endif
    int n,m;
    cin >> n >> m;
    fi(i,1,n) {
        int a,b;
        cin >> a >> b;
        point[i].x = a;
        point[i].y = b;
        f[i] = i;
    }
    fi(i,1,m){
        int a,b;
        cin >> a >> b;
        vis[a][b] = true;
        vis[b][a] = true;
        if(find(a)!=find(b))
        combin(a,b);
    }
    fi(i,1,n) fi(j,i+1,n){
        int a = point[i].x,b = point[i].y;
        int c = point[j].x,d = point[j].y;
        double p = sqrt((double)(c-a)*(c-a) + (double)(d-b)*(d-b));
        vec.pb({i,j,p});
    }
    sort(vec.begin(),vec.end());
    double ans = 0;
    fi(i,1,sz(vec)){
        int a = vec[i-1].a;
        int b = vec[i-1].b;
        if(!vis[a][b] && find(a) != find(b)) ans += vec[i-1].w,combin(a,b);
    }
    cout << setprecision(2);
    cout << fixed;
    cout << ans << endl;
    return 0;
}
posted @ 2022-03-22 10:55  Sun-Wind  阅读(27)  评论(0编辑  收藏  举报