热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

1.10HDU1007QuoitDesign

http:acm.hdu.edu.cnshowproblem.php?pid1007首先说明题意:一个名为quiot的游戏,类似与在商场玩的用圆环套玩具的游戏,但设计要求保证一次不

http://acm.hdu.edu.cn/showproblem.php?pid=1007

首先说明题意:一个名为quiot的游戏,类似与在商场玩的用圆环套玩具的游戏,但设计要求保证一次不应套中两个玩具。求计算最大的圆环半径。

于是可以建模为平面最近点对的经典分治问题。


bubuko.com,布布扣class="code_img_closed" id="code_img_closed_1f626629-2068-4006-82c2-4142fdd442e8"
src="https://img.php1.cn/3cd4a/1eebe/cd5/8343fdbffb0056b5.webp">bubuko.com,布布扣class="code_img_opened" id="code_img_opened_1f626629-2068-4006-82c2-4142fdd442e8"
Onclick="cnblogs_code_hide(‘1f626629-2068-4006-82c2-4142fdd442e8‘,event)"
src="https://img.php1.cn/3cd4a/1eebe/cd5/6789f68dabde0aed.png">

1 #include
2 #include
3 #include
4 using namespace std;
5 const int MAXN = 100100;
6 struct Point{
7 double x, y;
8 }x[MAXN];
9 int y[MAXN], z[MAXN];
10 bool cmpx(const Point& a, const Point& b)
11 { return a.x < b.x; }
12 bool cmpy(const int& a, const int &b)
13 { return x[a].y < x[b].y; }
14 inline double dis(Point a, Point b)
15 { return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y); }
16
17 void Merge(int z[], int y[], int l, int r, int m)
18 {
19 int i = l, j = m+1, k = l;
20 while(i <= m && j <= r)
21 if(x[z[i]].y <= x[z[j]].y) y[k++] = z[i++];
22 else y[k++] = z[j++];
23 while(i <= m) y[k++] = z[i++];
24 while(j <= r) y[k++] = z[j++];
25 }
26
27 double close(int y[], int z[], int l, int r)
28 {
29 if(l+1 == r)
30 return dis(x[l], x[r]);
31 if(l+2 == r)
32 return min(dis(x[l], x[l+1]), min(dis(x[l+1], x[r]), dis(x[l], x[r])));
33 int m = l+r>>1;
34 for(int i=l, j=m+1, k=l ; k<=r ; k++)
35 if(y[k] > m) z[j++] = y[k];
36 else z[i++] = y[k];
37 double res = min(close(z, y, l, m), close(z, y, m+1, r));
38 Merge(z, y, l, r, m);
39 int rt = l;
40 for(int i=l ; i<=r ; i++)
41 if(fabs(x[y[i]].x - x[y[m]].x) < res)
42 z[rt++] = y[i];
43 for(int i=l ; i)
44 for(int j=i+1 ; j)
45 {
46 if(x[z[j]].y - x[z[i]].y >= res) break;
47 res = min(res, dis(x[z[i]], x[z[j]]));
48 }
49 return res;
50 }
51
52 int main()
53 {
54 // freopen("input", "r", stdin);
55 int n;
56 while(scanf("%d", &n), n)
57 {
58 for(int i=0 ; i)
59 scanf("%lf %lf", &x[i].x, &x[i].y), y[i] = i;
60 sort(x, x+n, cmpx);
61 sort(y, y+n, cmpy);
62 printf("%.2lf\n", sqrt(close(y, z, 0, n-1))/2);
63 }
64 }

class="cnblogs_code_collapse">View Code

1.
X,Y,Z数组的功能:X数组存放了所有点记录,按照x坐标排序,在每一个分治函数中都不改变;Y数组用于开始也存放了所有点记录,按照y坐标排序,Z是临时数组。这里用了一个很巧妙的方法使空间复杂度降为O(n),即让YZ轮换。每次分治时,我们要保证传入的Y数组在相应[l,
r]范围内是不变的
。我们可以把[l, m]部分和[m+1, r]部分的点分别按照y升序放入Z数组相应的[l, r],这样Y数组[l,
r]部分就没有用了,可以让Y数组起到下一次分治临时数组的功能(代码反映在:close(z, y, l, m), close(z, y, m+1,
r))。但是当分治完需要回复Y数组(记得一开始我们说需要保证Y数组的不变性),而根据递归定义,传入的Z的[l, m]和[m+1,
r]部分是不变的,故可以归并恢复Y数组。

2. 所谓d*2d内最多有六个点体现在那里?我们要用分治构造出整体O(nlogn)的算法,就要求符合T(n) = 2T(n/2) +
O(n)的递归式,即close函数内只能进行O(n)的算法。34-36行把Y数组按照m分割为两个部分放入Z数组,38行Merge归并构造Y,39-42行将距离m两边d的所有点存入Z数组,均是一个for循环从l到r,故符合O(n)复杂度。43-48行有两个for循环,其功能是在候选点集中一一计算距离,正是这里体现了鸽笼定理证出的“六个点”。内部的break可以保证第二个循环至多执行3次。所以也是O(n)的复杂度。

3. 为什么不需要l == r的判断?由于我们单独处理的l+2 == r和l+1 == r,这样对r-l >= 3执行m =
l+r>>1不可能出现m==l或m==r。

4. 还有一个需要注意的地方:我们在close函数中对Y和Z数组都限定了范围:l-r,即使Z是临时数组,我们可以利用的也只有[l,
r]的范围。这样才有了算法的正确性。

5.
令我费解的一点是,如果把第60行的sort排序换成qsort,就会WA(改61行的不会WA)。。。这让我这个C爱好者感到好桑心,每次码题都强迫征似的只包含C的头文件,结果WA了无数次。。。这里贴上qsort的代码,可能是比较函数错了吧。。。求大神指出为何会错。


bubuko.com,布布扣class="code_img_closed" id="code_img_closed_2b7f3279-4150-4a2e-88a6-03ae8ad01b24"
src="https://img.php1.cn/3cd4a/1eebe/cd5/8343fdbffb0056b5.webp">bubuko.com,布布扣class="code_img_opened" id="code_img_opened_2b7f3279-4150-4a2e-88a6-03ae8ad01b24"
Onclick="cnblogs_code_hide(‘2b7f3279-4150-4a2e-88a6-03ae8ad01b24‘,event)"
src="https://img.php1.cn/3cd4a/1eebe/cd5/6789f68dabde0aed.png">

1 #include
2 #include <string.h>
3 #include
4 #include
5 const int MAXN = 100100;
6 struct Point{
7 double x, y;
8 }x[MAXN];
9 int y[MAXN], z[MAXN];
10 int cmpx(const void* a, const void* b)
11 { return ((Point*)a)->x - ((Point*)b)->x; }
12 int cmpy(const void* a, const void* b)
13 { return x[(*(int*)a)].y - x[(*(int*)b)].y; }
14 inline double min(double a, double b)
15 { return a a : b; }
16 inline double dis(Point a, Point b)
17 { return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y); }
18 void Merge(int z[], int y[], int l, int r, int m)
19 {
20 int i = l, j = m+1, k = l;
21 while(i <= m && j <= r)
22 if(x[z[i]].y <= x[z[j]].y) y[k++] = z[i++];
23 else y[k++] = z[j++];
24 while(i <= m) y[k++] = z[i++];
25 while(j <= r) y[k++] = z[j++];
26 }
27
28 double close(int y[], int z[], int l, int r)
29 {
30 if(l+1 == r)
31 return dis(x[l], x[r]);
32 if(l+2 == r)
33 return min(dis(x[l], x[l+1]), min(dis(x[l+1], x[r]), dis(x[l], x[r])));
34 int m = l+r>>1;
35 for(int i=l, j=m+1, k=l ; k<=r ; k++)
36 if(y[k] > m) z[j++] = y[k];
37 else z[i++] = y[k];
38 double res = min(close(z, y, l, m), close(z, y, m+1, r));
39 Merge(z, y, l, r, m);
40 int rt = l;
41 for(int i=l ; i<=r ; i++)
42 if(fabs(x[y[i]].x - x[y[m]].x) < res)
43 z[rt++] = y[i];
44 for(int i=l ; i)
45 for(int j=i+1 ; j)
46 {
47 if(x[z[j]].y - x[z[i]].y >= res) break;
48 res = min(res, dis(x[z[i]], x[z[j]]));
49 }
50 return res;
51 }
52
53 int main()
54 {
55 // freopen("input", "r", stdin);
56 int n;
57 while(scanf("%d", &n), n)
58 {
59 for(int i=0 ; i)
60 scanf("%lf %lf", &x[i].x, &x[i].y), y[i] = i;
61 qsort(x, n, sizeof(Point), cmpx);
62 qsort(y, n, sizeof(int), cmpy);
63 printf("%.2lf\n", sqrt(close(y, z, 0, n-1))/2);
64 }
65 }

class="cnblogs_code_collapse">View Code

 

当然我还看了网上的做法:我看到网上的好多方法并没有用Merge操作,代码比较短,于是自己照着写了一遍


bubuko.com,布布扣class="code_img_closed" id="code_img_closed_ae0fa176-5490-4c62-9575-c51c0b268be2"
src="https://img.php1.cn/3cd4a/1eebe/cd5/8343fdbffb0056b5.webp">bubuko.com,布布扣class="code_img_opened" id="code_img_opened_ae0fa176-5490-4c62-9575-c51c0b268be2"
Onclick="cnblogs_code_hide(‘ae0fa176-5490-4c62-9575-c51c0b268be2‘,event)"
src="https://img.php1.cn/3cd4a/1eebe/cd5/6789f68dabde0aed.png">

1 #include
2 #include <string.h>
3 #include
4 #include
5 #include
6 using namespace std;
7 #define dis(a, b) (((a->x-b->x)*(a->x-b->x) + (a->y-b->y)*(a->y-b->y)))
8 const int MAXN = 100100;
9 struct Point{
10 double x, y;
11 }p[MAXN], *px[MAXN], *py[MAXN];
12 bool cmpx( Point *p1, Point *p2 )
13 { return p1->x x; }
14 bool cmpy( Point *p1, Point *p2 )
15 { return p1->y y; }
16
17 double close(int l, int r)
18 {
19 if(l+1 == r)
20 return dis(px[l], px[r]);
21 if(l+2 == r)
22 return min(dis(px[l], px[l+1]), min(dis(px[l+1], px[r]), dis(px[l], px[r])));
23 int m = l+r>>1, rt = 0;
24 double d = min(close(l, m), close(m+1, r));
25 for(int i=l ; i<=r ; i++)
26 if(px[i]->x >= px[m]->x - d && px[i]->x <= px[m]->x + d)
27 py[rt++] = px[i];
28 sort(py, py+rt, cmpy);
29 for(int i=0 ; i)
30 for(int j=i+1 ; j)
31 {
32 if(py[j]->y - py[i]->y >= d) break;
33 d = min(d, dis(py[i], py[j]));
34 }
35 return d;
36 }
37
38 int main()
39 {
40 // freopen("input", "r", stdin);
41 int n;
42 while(scanf("%d", &n), n)
43 {
44 for(int i=0 ; i)
45 scanf("%lf %lf", &p[i].x, &p[i].y), px[i] = &p[i];
46 sort(px, px+n, cmpx);
47 printf("%.2lf\n", sqrt(close(0, n-1))/2.0);
48 }
49 }

View Code

从评测结果上看,比我的快几十毫秒吧,但从复杂度上来说,这是个更渣的算法。在第28行出close函数里用了一个排序函数,虽然表面上看只排了rt个元素,但最坏情况下rt会等于r-l,这样递归方程变成了T(n)
= 2T(n/2) + O(nlogn),根据主定理,总复杂度O(n) =
nlognlogn。从复杂度上分析这种方式更糟糕,但hdu上结果跟nlogn的结果差不多,可能还是数据太小的缘故吧。

不知为何,把sort换为qsort一样会WA,而且是在我仔细看了qsort的用法后。。。看来开学需要向人好好请教下qsort的用法了。


推荐阅读
  • egg实现登录鉴权(七):权限管理
    权限管理包含三部分:访问页面的权限,操作功能的权限和获取数据权限。页面权限:登录用户所属角色的可访问页面的权限功能权限:登录用户所属角色的可访问页面的操作权限数据权限:登录用户所属 ... [详细]
  • 本文介绍了用户界面(User Interface, UI)的基本概念,以及在iOS应用程序中UIView及其子类的重要性和使用方式。文章详细探讨了UIView如何作为用户交互的核心组件,以及它与其他UI控件和业务逻辑的关系。 ... [详细]
  • 本文由chszs撰写,详细介绍了Apache Mina框架的核心开发流程及自定义协议处理方法。文章涵盖从创建IoService实例到协议编解码的具体步骤,适合希望深入了解Mina框架应用的开发者。 ... [详细]
  • LeetCode 102 - 二叉树层次遍历详解
    本文详细解析了LeetCode第102题——二叉树的层次遍历问题,提供了C++语言的实现代码,并对算法的核心思想和具体步骤进行了深入讲解。 ... [详细]
  • selenium通过JS语法操作页面元素
    做过web测试的小伙伴们都知道,web元素现在很多是JS写的,那么既然是JS写的,可以通过JS语言去操作页面,来帮助我们操作一些selenium不能覆盖的功能。问题来了我们能否通过 ... [详细]
  • 本文介绍了一个来自AIZU ONLINE JUDGE平台的问题,即清洁机器人2.0。该问题来源于某次编程竞赛,涉及复杂的算法逻辑与实现技巧。 ... [详细]
  • 本文提供了一个关于AC自动机(Aho-Corasick Algorithm)的详细解析与实现方法,特别针对P3796题目进行了深入探讨。文章不仅涵盖了AC自动机的基本概念,还重点讲解了如何通过构建失败指针(fail pointer)来提高字符串匹配效率。 ... [详细]
  • 本报告记录了嵌入式软件设计课程中的第二次实验,主要探讨了使用KEIL V5开发环境和ST固件库进行GPIO控制及按键响应编程的方法。通过实际操作,加深了对嵌入式系统硬件接口编程的理解。 ... [详细]
  • 如何高效渲染JSON数据
    本文介绍了在控制器中返回JSON结果的方法,并详细说明了如何利用jQuery处理和展示这些数据,为Web开发提供了实用的技巧。 ... [详细]
  • Awk是一款功能强大的文本分析与处理工具,尤其在数据解析和报告生成方面表现突出。它通过读取由换行符分隔的记录,并按照指定的字段分隔符来划分和处理这些记录,从而实现复杂的数据操作。 ... [详细]
  • 3DSMAX制作超现实的体育馆模型
    这篇教程是向脚本之家的朋友介绍3DSMAX制作超现实的体育馆模型方法,教程制作出来的体育馆模型非常地不错,不过教程有点难度,需要有一定基础的朋友学习,推荐到脚本之家,喜欢的朋友可 ... [详细]
  • 默认情况下,Git 使用 Nano 编辑器进行提交信息的编辑,但如果您更喜欢使用 Vim,可以通过简单的配置更改来实现这一变化。本文将指导您如何通过修改全局配置文件来设置 Vim 作为默认的 Git 提交编辑器。 ... [详细]
  • 探讨如何在映射文件中处理重复的属性字段,以避免数据操作时出现错误。 ... [详细]
  • Windows环境下Oracle数据库迁移实践
    本文详细记录了一次在Windows操作系统下将Oracle数据库的控制文件、数据文件及在线日志文件迁移至外部存储的过程,旨在为后续的集群环境部署做好准备。 ... [详细]
  • 本文探讨了线性表中元素的删除方法,包括顺序表和链表的不同实现策略,以及这些策略在实际应用中的性能分析。 ... [详细]
author-avatar
dtd3795290
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有