bzoj2458: [BeiJing2011]最小三角形(分治+几何)

题目链接:bzoj2458: [BeiJing2011]最小三角形

学习推荐博客:分治法编程问题之最接近点对问题的算法分析

题解:先将所有点按x值排列,然后每次将当前区间[l,r]分成左右两半递归求解周长最小三角形。考虑到两半区间之间可能有连成最小三角形的情况,设dd为两半区间中最小三角形周长的最小值,筛选满足要求的点(x值与中点坐标x值的距离小于dd),然后按y值排序,进而暴搜出周长最小三角形。

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<queue>
 4 #include<cstring>
 5 #include<string>
 6 #include<algorithm>
 7 #define CLR(a,b) memset((a),(b),sizeof((a)))
 8 using namespace std;
 9
10 typedef long long ll;
11 const double inf = 0x3f3f3f3f;
12 const int N = 2e5+1;
13 int n;
14 struct Point{
15     int x, y;
16 }a[N], midp[N];
17 double dis(Point a, Point b){
18     return sqrt(1.*(a.x - b.x)*(a.x - b.x) + 1.*(a.y - b.y)*(a.y - b.y));
19 }
20 bool cmp1(Point a, Point b){
21     return a.x < b.x;
22 }
23 bool cmp2(Point a, Point b){
24     return a.y < b.y;
25 }
26 double solve(int l, int r){
27     if(l == r ||l + 1 == r) return inf;
28     if(l + 2 == r) return dis(a[l],a[l+1]) + dis(a[l+1],a[r]) + dis(a[l],a[r]);
29
30     int m = l + (r-l)/2;
31     double d1 = solve(l, m);
32     double d2 = solve(m+1, r);
33     double d = min(d1, d2);
34     double dd = d/2.0;
35     double ans = d;
36
37     int cnt = 0, i, j, k;
38     for(i = l; i <= r; ++i)
39         if(fabs(a[m].x - a[i].x) <= dd)
40             midp[++cnt] = a[i];
41     sort(midp+1, midp+1+cnt, cmp2);
42
43     for(i = 1; i < cnt-1; ++i){
44         for(j = i+1; j < cnt; ++j){
45             if(midp[j].y - midp[i].y > dd)
46                 break;
47             for(k = j+1; k <= cnt; ++k){
48                 if(midp[k].y - midp[i].y > dd)
49                     break;
50                 double c = dis(midp[i],midp[j])+dis(midp[j],midp[k])+dis(midp[i],midp[k]);
51                 ans = min(ans, c);
52             }
53         }
54     }
55     return ans;
56 }
57 int main(){
58     scanf("%d", &n);
59     for(int i = 1; i <= n; ++i)
60         scanf("%d%d", &a[i].x, &a[i].y);
61     sort(a+1, a+1+n, cmp1);
62     printf("%.6lf\n", solve(1,n));
63     return 0;
64 }

时间: 2024-08-24 05:10:37

bzoj2458: [BeiJing2011]最小三角形(分治+几何)的相关文章

BZOJ2458 [BeiJing2011]最小三角形

Description Xaviera现在遇到了一个有趣的问题. 平面上有N个点,Xaviera想找出周长最小的三角形. 由于点非常多,分布也非常乱,所以Xaviera想请你来解决这个问题. 为了减小问题的难度,这里的三角形也包括共线的三点. Input 第一行包含一个整数N表示点的个数. 接下来N行每行有两个整数,表示这个点的坐标. Output 输出只有一行,包含一个6位小数,为周长最短的三角形的周长(四舍五入). Sample Input 4 1 1 2 3 3 3 3 4 Sample

bzoj2458: [BeiJing2011]最小三角形 最近点对

类似分治最近点对的方法乱搞一下就行. #include<bits/stdc++.h> #define N 200010 #define M (s+t>>1) using namespace std; struct vec{ int x,y; }u[N],v[N]; bool foo(vec a,vec b){ return a.x<b.x; } bool bar(vec a,vec b){ return a.y<b.y; } double sqr(double x){

bzoj 2458: [BeiJing2011]最小三角形 题解

[前言]话说好久没有写题解了.到暑假了反而忙.o(╯□╰)o [原题] 2458: [BeiJing2011]最小三角形 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 574  Solved: 177 [Submit][Status] Description Xaviera如今遇到了一个有趣的问题. 平面上有N个点.Xaviera想找出周长最小的三角形. 因为点许多.分布也很乱,所以Xaviera想请你来解决问题. 为了减小问题的难度,这里的三

BZOJ 2458 BeiJing2011 最小三角形 计算几何+分治

题目大意:给定平面上的一个点集,求这个点集所能组成的周长最小的三角形 与平面最近点对一个道理- - 这个题也是分治做法 做法如下: 1.记录全局答案ans 2.将所有点按照x值排序 3.定义Solve(l,r)为处理[l,r]区间内的最小三角形 4.对于每层Solve(l,r),将当前区间分成左右两部分,分别递归处理 5.两侧的最小三角形都以处理完毕,现在我们要处理的就是两区间之间的点构成的三角形 6.将本层中与点mid的横坐标之差不超过ans/2的点拎出来,按照纵坐标排序 (其实这步可以直接递

BZOJ 2458: [BeiJing2011]最小三角形 | 平面分治

题目: 给出若干个点 求三个点构成的周长最小的三角形的周长(我们认为共线的三点也算三角形) 题解: 可以参考平面最近点对的做法 只不过合并的时候改成枚举三个点更新周长最小值,其他的和最近点对大同小异 2#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define N 200010 #define INF 1e20 using namespace std; int

BZOJ 2458 BeiJing 2011 最小三角形 分治

题目大意:给出平面上一些点,问这些点组成的最小周长三角形的周长是多少. 思路:与平面最近点对类似的思想,先按照x值排序,通过全局目前搜到的最优解来缩小分治之后需要暴力枚举的范围.具体来说,递归的终止条件是需要处理的点数小于一定数量,就在这些点中暴力枚举来更新答案.这个值经过测定,在这个题中20左右为最快的.具体怎么算我也不知道.. 之后每处理一段区间,先递归处理左右区间来更新答案,弄出一个中轴来,设目前为止最优的答案是c,那么只保留距离中轴距离不超过c / 2的点来处理,不难证明在这之外的点不可

BZOJ 2458 最小三角形 | 平面分治

BZOJ 2458 最小三角形 题面 一个平面上有很多点,求他们中的点组成的周长最小的三角形的周长. 题解 跟平面最近点对差不多,也是先把区间内的点按x坐标从中间分开,递归处理,然后再处理横跨中线的三角形. 如何缩小范围?设左右两个子区间发现的最小周长是d,则与中线距离超过d / 2都没有用了,对于一个点,所有与它距离超过d / 2的点也都没有用. #include <cstdio> #include <cstring> #include <cmath> #includ

BZOJ 2229 ZJOI2011 最小割 最小割+分治 400AC达成&amp;&amp;2000Submission达成

题目大意:给定一个图,多次询问有多少个点对之间的最小割小于等于某个值 最小割分治- - 首先朴素的想法是做O(n^2)遍网络流 但是这样显然是过不去的 根据一些结论,最小割最多有n-1个,这n-1个最小割构成一个最小割树 别问我为什么- - 因此我们分治寻找这n-1个最小割 每层分治,先任选两个点作为源汇做一遍最小割 然后找出S集和T集,对所有S集的点和T集的点构成的点对用本次得到的最小割更新一遍 注意更新的是全部S集和全部T集,不只是本次分治内部的S集和T集 然后将本次分治的点分成S集和T集,

最小割分治(最小割树):BZOJ2229 &amp;&amp; BZOJ4519

定理:n个点的无向图的最小割最多n-1个. 可能从某种形式上形成了一棵树,不是很清楚. 最小割分治:先任选两个点求一边最小割,然后将两边分别递归,就能找到所有的最小割. 这两个题是一样的,直接搬dinic模板即可. BZOJ2229: 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #define mem(a,k) memset(a,k,siz