• 【luogu P1783 海滩防御】 题解


    题目链接:https://www.luogu.org/problemnew/show/P1783

    先把题目改造一下:题目所求是要一条能从0列到n列的路径,使其路径上的最大边长一半最小。

    为什么是一半呢?

    考虑半径这个东西,假如两个点之间距离为d,半径分别为r1,r2。需满足r1 + r2 >= d

    若当前d为所求路径上的最大边长,那么当且仅当r1 = r2 = d/2时有最小的r满足条件,否则若一个r < d/2,另一个就会是r > d/2,取最大的r还是>d/2。

    那么剩下的问题是怎么求出符合条件(覆盖0—n列)的路径。

    如果我们把每个线段(两端点+线长)看作一个集合,只要有x坐标为0的线段和x坐标为n的线段在一个集合就可以证明0—n被覆盖了。

    因为在0列和n列上不一定有哨塔,所以我们考虑点到0列和n列的线段也是一个集合。

    注意的就是在把每一个点到0和n分别作出垂线段来,而不是最近的点分别到0和n的垂线段。(我在这卡了30分)

    处理集合问题用——并查集。

    那么剩下的只有求出最短的r来,想到贪心的策略。

    ——类似kruskal的算法实现。

    code:

    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int maxn = 1010;
    struct edge{
    	int u, v; 
    	double w;
    }e[1000010];
    bool cmp(edge x, edge y)
    {
    	return x.w < y.w;
    }
    int n, m, cnt, fa[maxn];
    int dx[maxn], dy[maxn];
    double distance(int x1, int y1, int x2, int y2)
    {
    	return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
    }
    void init()
    {
    	for(int i = 0; i <= m+1; i++) fa[i] = i;
    	
    	for(int i = 1; i < m; i++)
    		for(int j = i+1; j <= m; j++)
    		e[++cnt].u = i, e[cnt].v = j, e[cnt].w = distance(dx[i], dy[i], dx[j], dy[j])/2;
    	for(int i = 1; i <= m; i++)
    		e[++cnt].u = i, e[cnt].v = 0, e[cnt].w = dx[i];
    	for(int i = 1; i <= m; i++)
    		e[++cnt].u = i, e[cnt].v = m+1, e[cnt].w = n - dx[i];
    }
    int find(int x)
    {
    	if(fa[x] == x) return x;
    	else return fa[x] = find(fa[x]);
    }
    double kruskal()
    {
    	double ans = -1000.0;
    	sort(e+1, e+cnt+1, cmp);
    	for(int i = 1; i <= cnt; i++)
    	{
    		int fu = find(e[i].u); int fv = find(e[i].v);
    		if(fu != fv) 
    		{
    			fa[fu] = fv;
    			ans = max(ans, e[i].w);	
    		}
    		int f0 = find(0); int fm = find(m+1);
    		if(f0 == fm) break;
    	}
    	return ans;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	int L = n+2, R = -1;
    	for(int i = 1; i <= m; i++)
    	scanf("%d%d",&dx[i],&dy[i]);
    	init();
    	printf("%0.2f",kruskal());
    	return 0;
    }
    
  • 相关阅读:
    history对象
    排序算法总结
    Boltzmann机
    Sort Colors
    First Missing Positive
    Sort List
    Insertion Sort List
    Merge Two Sorted Lists
    Merge Sorted Array
    Sum Root to Leaf Numbers
  • 原文地址:https://www.cnblogs.com/MisakaAzusa/p/10999631.html
Copyright © 2020-2023  润新知