POJ 2349 Arctic Network

来源:互联网 发布:azure 阿里云 编辑:程序博客网 时间:2024/05/21 10:30

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=33862#problem/K

最小生成树变形问题, 题目大意就是求解最小的D使得大于D的边被删除之后剩余图的连通分量的个数小于等于S.我们容易知道删除最小生成树上大于第S长的边删除恰好可以将该最小生成树分解成S个连通分量,且每个连通的分量内的距离均小于等于D.我想了一个大胆的想法一个图中最小生成树中的第K长的边肯定小于等于余生成树中第K长的边,因此可以保证最小生成树中的第K长的边是最小的(PS:以上结论成不成立我没证出来,然后我自己的也没找出反例来,想了一下应该是正确的).


#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>using namespace std;/*利用最小生成树上的边的性质:将最小生成树上大于第K长边的长度删除,可以将原图分解成K个连通分量*/const int MAXN = 510;const int MAXM = MAXN * MAXN;const int INF  = 0x3f3f3f3f;struct Point{    double x, y;    Point() {}    Point(double t_x, double t_y) : x(t_x), y(t_y) {}}p[MAXN];struct Edge{    int u, v;    double w;    Edge() {}    Edge(int t_u, int t_v, double t_w) : u(t_u), v(t_v), w(t_w) {}    friend bool operator< (const Edge &e1, const Edge &e2)    {        return e1.w < e2.w;    }}edge[MAXM];int parent[MAXN];double dis[MAXN];int N, S, P, cnt;double get_dis(const Point &p1, const Point &p2){    return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));}void init_set(){    memset(parent, -1, sizeof(parent));}int find_set(int x){    return parent[x] < 0 ? x : parent[x] = find_set(parent[x]);}void union_set(int x, int y){    int r1 = find_set(x), r2 = find_set(y);    if(r1 != r2)    {        if(parent[r2] < parent[r1])        {            parent[r2] += parent[r1];            parent[r1] = r2;        }        else        {            parent[r1] += parent[r2];            parent[r2] = r1;        }    }    return ;}double Kruskal(){    sort(edge + 1, edge + cnt + 1);    int num = 0; init_set();    for(int i = 1; i <= cnt; ++i)    {        if(find_set(edge[i].u) != find_set(edge[i].v))        {            union_set(edge[i].u, edge[i].v);            dis[++num] = edge[i].w;        }        if(num == P-1) break;    }    return dis[num-S+1];}int main(){    //freopen("aa.in", "r", stdin);    scanf("%d", &N);    while(N--)    {        scanf("%d %d", &S, &P);        for(int i = 1; i <= P; ++i)        {            scanf("%lf %lf", &p[i].x, &p[i].y);        }        cnt = 0;        for(int i = 1; i <= P; ++i)        {            for(int j = i + 1; j <= P; ++j)            {                edge[++cnt] = Edge(i, j, get_dis(p[i], p[j]));            }        }        printf("%.2lf\n", Kruskal());    }    return 0;}