热门标签 | 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的用法了。


推荐阅读
  • 本文介绍了一款用于自动化部署 Linux 服务的 Bash 脚本。该脚本不仅涵盖了基本的文件复制和目录创建,还处理了系统服务的配置和启动,确保在多种 Linux 发行版上都能顺利运行。 ... [详细]
  • QUIC协议:快速UDP互联网连接
    QUIC(Quick UDP Internet Connections)是谷歌开发的一种旨在提高网络性能和安全性的传输层协议。它基于UDP,并结合了TLS级别的安全性,提供了更高效、更可靠的互联网通信方式。 ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • 深入理解OAuth认证机制
    本文介绍了OAuth认证协议的核心概念及其工作原理。OAuth是一种开放标准,旨在为第三方应用提供安全的用户资源访问授权,同时确保用户的账户信息(如用户名和密码)不会暴露给第三方。 ... [详细]
  • 2023 ARM嵌入式系统全国技术巡讲旨在分享ARM公司在半导体知识产权(IP)领域的最新进展。作为全球领先的IP提供商,ARM在嵌入式处理器市场占据主导地位,其产品广泛应用于90%以上的嵌入式设备中。此次巡讲将邀请来自ARM、飞思卡尔以及华清远见教育集团的行业专家,共同探讨当前嵌入式系统的前沿技术和应用。 ... [详细]
  • 深入理解 Oracle 存储函数:计算员工年收入
    本文介绍如何使用 Oracle 存储函数查询特定员工的年收入。我们将详细解释存储函数的创建过程,并提供完整的代码示例。 ... [详细]
  • CSS 布局:液态三栏混合宽度布局
    本文介绍了如何使用 CSS 实现液态的三栏布局,其中各栏具有不同的宽度设置。通过调整容器和内容区域的属性,可以实现灵活且响应式的网页设计。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • PHP 5.2.5 安装与配置指南
    本文详细介绍了 PHP 5.2.5 的安装和配置步骤,帮助开发者解决常见的环境配置问题,特别是上传图片时遇到的错误。通过本教程,您可以顺利搭建并优化 PHP 运行环境。 ... [详细]
  • 深入解析Spring Cloud Ribbon负载均衡机制
    本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ... [详细]
  • 几何画板展示电场线与等势面的交互关系
    几何画板是一款功能强大的物理教学软件,具备丰富的绘图和度量工具。它不仅能够模拟物理实验过程,还能通过定量分析揭示物理现象背后的规律,尤其适用于难以在实际实验中展示的内容。本文将介绍如何使用几何画板演示电场线与等势面之间的关系。 ... [详细]
  • 本文介绍如何通过Windows批处理脚本定期检查并重启Java应用程序,确保其持续稳定运行。脚本每30分钟检查一次,并在需要时重启Java程序。同时,它会将任务结果发送到Redis。 ... [详细]
  • MySQL中枚举类型的所有可能值获取方法
    本文介绍了一种在MySQL数据库中查询枚举(ENUM)类型字段所有可能取值的方法,帮助开发者更好地理解和利用这一数据类型。 ... [详细]
  • 本文介绍如何在应用程序中使用文本输入框创建密码输入框,并通过设置掩码来隐藏用户输入的内容。我们将详细解释代码实现,并提供专业的补充说明。 ... [详细]
  • 本文详细介绍了如何通过命令行启动MySQL服务,包括打开命令提示符窗口、进入MySQL的bin目录、输入正确的连接命令以及注意事项。文中还提供了更多相关命令的资源链接。 ... [详细]
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社区 版权所有