3-点的坐标及最远距离问题

本文介绍了一种计算坐标轴上两点间最远可能距离的方法,包括两种不同的实现方式:一种只输出最远距离,另一种同时输出构成最远距离的点序列。

2018.7.29

3-0 最远距离

输入是一个n,表示坐标轴上点的个数,然后输入一系列的浮点数,第i个数字代表距离第i-1个点的距离的平方,那么第i个点可能在第i-1个点的左侧,也有可能是右侧,求出第n个点到第1个点的最远可能的距离。注意:第一个输入的点代表的是第一个点所在的具体坐标。

例如输入:

5

-5 4 2.25 1 0

输出为:

4.5

 

3-1 不仅要输出最远距离,还要输出这个构成最短距离的可能的点的序列。

例如刚才的输出为:

4.5

-5 -3 -1.5 -0.5


代码1:(自己写的):

#include <iostream>
#include <stdio.h>
#include <math.h>
const int x = 100;

using namespace std;

float a[x];         //数组用来保存输入的浮点型数
int main()
{
    int n;
    float sum;
    scanf("%d",&n);
    scanf("%f",&a[0]);
    for(int i=1;i<n;i++)
    {
        scanf("%f",&a[i]);
        a[i]=sqrt(a[i]);
    }
    for(int j=1;j<n;j++)
    {
        sum+=a[j];
    }
    printf("%0.1f\n",sum);

    for(int i=0;i<n-1;i++)
    {
        a[i+1]=a[i]+a[i+1];
        printf("%0.1f\t",a[i]);
    }

    return 0;
}

代码2:(西交wrong):

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <cmath>
using namespace std;
const int maxn = 100000;
typedef pair<int,int> P;
double out[maxn]; //
int main()
{
    int n;
    double x;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lf",&x);
        if(i==1) out[i]=x;
        else out[i]=out[i-1]+sqrt(x);
    }
    //out[1] out[1]+sqrt(x[2]) out[1]+sqrt(x[2])+sqrt(x[3])
    cout<<out[n]-out[1]<<endl;
    for(int i=1;i<=n;i++)
        cout<<out[i]<<" ";
    cout<<endl;
   return 0;
}

(感谢西交wrong学长提供以上题目练习)

<think>首先,用户的问题是:“我想在给定的坐标数组中,找出距离远的两个。请问find two points with maximum distance in a coordinate array。” 这是一个关于计算几何的问题,需要在集中找到距离远的两个。 关键- 输入:一个坐标数组,例如,[(x1, y1), (x2, y2), ..., (xn, yn)] 在二维平面上。 - 输出:距离远的两个,即距离对。 - 算法:我需要使用一个高效的算法来解决这个问题直接的方法是计算所有对之间的距离,然后取大值,但这种方法的时间复杂度是 O(n^2),对于大规模数据不高效。更好的方法是使用凸包(Convex Hull)算法,因为远的对必须在凸包的顶上。 步骤: 1. **计算凸包**:先找到集的凸包。凸包是包含所有小凸多边形。对(直径)必须在凸包的顶上。 2. **在凸包上找对**:一旦有了凸包,可以使用旋转卡壳(Rotating Calipers)算法在 O(n) 时间内找到对,其中 n 是凸包的顶数。 凸包算法: - 常用算法有 Graham Scan 或 Jarvis March。 - Graham Scan 的时间复杂度是 O(n log n),适合大多数情况。 旋转卡壳算法: - 用于在凸多边形上找到对。 - 基本思想:使用两个平行线“卡住”多边形,并旋转它们,计算对踵(antipodal points)之间的距离。 因此,完整的解决方案是: 1. 计算集的凸包。 2. 在凸包上应用旋转卡壳算法找到距离对。 现在,关于回答结构: - 系统级指令要求: - 行内数学表达式用 $...$,例如距离公式。 - 独立公式用 $$...$$。 - 使用中文回答。 - 生成相关问题- 引用标识:在引用的段落末尾添加 [^number],但用户提供的引用似乎不相关,所以我应该忽略它们,除非有直接关联。 - 用户可见层:回答结构清晰,逐步解决问题,保证真实可靠。 用户提供的引用: - [^1] 是关于树结构的描述。 - [^2] 是关于天线数据的。 - [^3] 是关于链接器设置的。 这些与当前问题无关,所以我不会使用它们。系统指令说“上述引用仅供参考”,所以我应该基于问题本身回答。 回答结构: 1. **解释问题**:简要描述问题。 2. **介绍算法**:解释为什么使用凸包和旋转卡壳。 3. **步骤详解**: - 步骤1:计算凸包(例如,使用 Graham Scan)。 - 步骤2:在凸包上应用旋转卡壳算法。 4. **伪代码或代码示例**:提供代码来演示,但用户没有指定语言,我可以使用Python。 5. **时间复杂度**:讨论效率。 6. **生成相关问题**:在后添加相关问题。 数学公式: - 距离公式:对于两个 $(x1, y1)$ 和 $(x2, y2)$,距离是 $\sqrt{(x2 - x1)^2 + (y2 - y1)^2}$。 - 在旋转卡壳中,可能需要向量叉积等。 代码示例: - 用Python实现 Graham Scan 和旋转卡壳。 相关问题- 基于这个主题生成3问题终回答大纲: 1. 开头:解释问题。 2. 算法选择理由。 3. 详细步骤: - 凸包计算。 - 旋转卡壳。 4. 代码示例(Python)。 5. 时间复杂度分析。 6. 相关问题。</think>### 找出集中距离远的两个 在计算几何中,给定一个坐标数组(例如,在二维平面上的集 $S = \{(x_1, y_1), (x_2, y_2), \dots, (x_n, y_n)\}$),找出距离远的两个(即大欧氏距离对)是一个常见问题。直接计算所有对的距离(时间复杂度 $O(n^2)$)在大规模数据下效率低下。高效的方法是使用 **凸包(Convex Hull)** 和 **旋转卡壳(Rotating Calipers)** 算法,因为对必然位于凸包的顶上。以下是逐步解决方案,使用 Python 实现。 #### 算法步骤 1. **计算凸包(Convex Hull)**: 凸包是包含所有小凸多边形。对一定在凸包的顶上。使用 **Graham Scan** 算法(时间复杂度 $O(n \log n)$): - **排序**:以 $y$ 坐标小的为基准(若有平局,取 $x$ 小),按极角排序剩余- **构建凸包**:使用栈维护凸包顶,通过叉积判断是否在凸包上。叉积公式: $$ \text{cross}(p, q, r) = (q_x - p_x)(r_y - p_y) - (q_y - p_y)(r_x - p_x) $$ 如果 $\text{cross}(p, q, r) > 0$,则 $r$ 在向量 $pq$ 的逆时针方向。 2. **在凸包上找对(旋转卡壳算法)**: 旋转卡壳算法在凸包顶上高效找到对(时间复杂度 $O(n)$): - **初始化**:取凸包的第一个 $p$,找到其“对踵” $q$(即距离 $p$ 远的)。 - **旋转**:顺时针移动 $p$,同时更新 $q$ 以保持距离。计算距离,并记录大值。 - **距离公式**:两 $(x_i, y_i)$ 和 $(x_j, y_j)$ 的欧氏距离为 $\sqrt{(x_j - x_i)^2 + (y_j - y_i)^2}$。 #### Python 代码实现 以下代码实现了上述算法。输入是一个坐标列表,输出是距离远的两个及其距离。 ```python import math from functools import cmp_to_key def cross(o, a, b): """计算叉积: 向量 oa 与 ob 的叉积""" return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]) def graham_scan(points): """计算凸包: 使用 Graham Scan 算法""" n = len(points) if n <= 3: return points # 找到 y 小(或 x 小)的作为基准 pivot = min(points, key=lambda p: (p[1], p[0])) # 按极角排序(使用叉积) sorted_pts = sorted(points, key=cmp_to_key(lambda a, b: cross(pivot, a, b))) sorted_pts.remove(pivot) sorted_pts = [pivot] + sorted_pts # 构建凸包栈 stack = [sorted_pts[0], sorted_pts[1]] for i in range(2, n): while len(stack) >= 2 and cross(stack[-2], stack[-1], sorted_pts[i]) <= 0: stack.pop() stack.append(sorted_pts[i]) return stack def rotating_calipers(hull): """在凸包上找对: 使用旋转卡壳算法""" n = len(hull) if n == 2: return hull[0], hull[1], math.dist(hull[0], hull[1]) # 初始化 p1, p2 = 0, 1 max_dist = 0 max_pair = (hull[0], hull[1]) # 遍历所有边 for i in range(n): j = (i + 1) % n edge_vec = (hull[j][0] - hull[i][0], hull[j][1] - hull[i][1]) # 找到当前边的对踵 while True: next_p = (p2 + 1) % n # 计算高度(叉积表示面积,除以底边长得高度) height = abs(cross(hull[i], hull[j], hull[next_p])) / math.dist(hull[i], hull[j]) curr_height = abs(cross(hull[i], hull[j], hull[p2])) / math.dist(hull[i], hull[j]) if height > curr_height: p2 = next_p else: break # 计算距离并更新大值 dist = math.dist(hull[i], hull[p2]) if dist > max_dist: max_dist = dist max_pair = (hull[i], hull[p2]) return max_pair[0], max_pair[1], max_dist # 示例用法 if __name__ == "__main__": # 输入集 points = [(0, 0), (1, 1), (2, 2), (3, 3), (1, 0), (0, 1)] # 步骤1: 计算凸包 hull = graham_scan(points) print(f"凸包顶: {hull}") # 步骤2: 找对 p1, p2, max_distance = rotating_calipers(hull) print(f"对: {p1} 和 {p2}, 距离: {max_distance:.2f}") ``` #### 输出示例 对于输入集 `[(0, 0), (1, 1), (2, 2), (3, 3), (1, 0), (0, 1)]`: - 凸包顶:`[(0, 0), (3, 3), (1, 0), (0, 1)]`(具体顺序可能因实现而异)。 - 对:`(0, 0)` 和 `(3, 3)`,距离约 $4.24$。 #### 算法分析 - **时间复杂度**: - 凸包计算:$O(n \log n)$(Graham Scan 的排序步骤)。 - 旋转卡壳:$O(n)$(凸包顶数)。 - 总体:$O(n \log n)$,远优于暴力法的 $O(n^2)$。 - **空间复杂度**:$O(n)$(存储凸包)。 - **适用性**:适用于二维集。对于更高维度,问题更复杂(如三维时需用凸包和更高级算法)。 #### 注意事项 - 输入集应无重复- 代码假设集在二维平面;扩展到三维需修改凸包算法(如 QuickHull)。 - 如果集已排序或部分有序,可优化凸包计算[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值