{ }codelper
平方根溢出输出小数P0233

送货无人机飞了多远

送货无人机从基地 (0, 0, 0) 出发,按给定顺序经过 n 个送货点,然后返回基地。
第一行给出送货点数 n。
接下来 n 行按经过的顺序给出送货点的坐标 x、y、z(厘米),用空格分开,每行一个。
无人机从一个地点直线飞到下一个地点。
两地之间的距离是 x、y、z 之差各自平方后相加的和的平方根。
共有 n + 1 段:第 1 段从基地到第一个点,第 k 段从第 k-1 个点到第 k 个点,第 n + 1 段从第 n 个点回到基地。
可能连续出现同一个点,也可能出现与基地相同的点,这时该段距离为 0。
从第 1 段到第 n + 1 段,每飞完一段,输出一行到此为止飞过的距离之和。
距离之和四舍五入到小数点后第二位,小数点后正好写两位(5 写成 5.00)。
为了让四舍五入没有歧义,所有要输出的和乘以 100 后,小数部分都不会在 0.4 到 0.6(含)之间。
最后一行输出最长的一段的编号。
如果有多段同为最长,输出其中最小的编号。

输入
1 ≤ n ≤ 1,000,-1,000,000 ≤ x, y ≤ 1,000,000,0 ≤ z ≤ 100,000(都是整数),没有要输出的和 × 100 的小数部分在 0.4~0.6 的输入
输出
n + 1 行:每段之后的累计距离(保留两位小数) / 最后一行:最长一段的编号
样例 1 · stdin
2
3 4 0
3 4 12
stdout
5.00
17.00
30.00
3
样例 2 · stdin
4
2 0 0
2 0 0
5 0 0
5 4 0
stdout
2.00
2.00
5.00
9.00
15.40
5
main.py
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 8 种语言题解

平方根:Python math.sqrt(或 ** 0.5)、JS/TS Math.sqrt、Java Math.sqrt、C# Math.Sqrt、C sqrt(<math.h>,链接时加 -lm)、C++ std::sqrt(<cmath>)、Craykon 数学.平方根。
它们都返回 double,像 long len = sqrt(...) 这样存进整数变量,5.83 就变成 5。
平方之前要先看大小。
坐标差可达 2×10^6,平方后是 4×10^12,32 位 int 只要差达到 46,341,平方就会溢出。
Java、C# 把坐标读成 long,C、C++ 读成 long long 再相乘。
Python 整数没有大小限制,JS、TS、Craykon 的数在 2^53 以内整数是精确的,所以三个平方之和(约 8×10^12)也完全正确。
用 C 或 C# 的 float 累加总和只有约七位有效数字,到几十亿厘米时小数位就错了。
要用 double。
输出:Python f"{total:.2f}"、JS/TS toFixed(2)、Java String.format(Locale.ROOT, "%.2f", total)、C# ToString("F2", CultureInfo.InvariantCulture)、C/C++ printf("%.2f")、Craykon 字符.保留小数(total, 2)。
像 Math.floor(total * 100) / 100 这样向下取整,就成了截断而不是四舍五入。
最长的一段可以不开平方,直接比较整数的平方和,这样就不用考虑浮点误差。
用 > 比较,长度相同时保留前面的编号。
为了不漏掉回基地的第 n + 1 段,在坐标列表末尾再加一个 (0, 0, 0),一个循环就能搞定。

Pythonmain.py · 18 行
import math n = int(input())points = [tuple(map(int, input().split())) for _ in range(n)]points.append((0, 0, 0))  # 마지막 구간은 기지로 돌아오는 길 cur = (0, 0, 0)total = 0.0best, best_sq = 1, -1for i, p in enumerate(points, start=1):    dx, dy, dz = p[0] - cur[0], p[1] - cur[1], p[2] - cur[2]    sq = dx * dx + dy * dy + dz * dz  # 정수 그대로 비교한다    total += math.sqrt(sq)    print(f"{total:.2f}")    if sq > best_sq:        best, best_sq = i, sq    cur = pprint(best)
JavaScriptmain.js · 26 行
const nums = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const n = nums[0];const points = [];for (let i = 0; i < n; i++) points.push(nums.slice(1 + 3 * i, 4 + 3 * i));points.push([0, 0, 0]); // 마지막 구간은 기지로 돌아오는 길 let cur = [0, 0, 0];let total = 0;let best = 1;let bestSq = -1;const out = [];points.forEach((p, i) => {  const dx = p[0] - cur[0];  const dy = p[1] - cur[1];  const dz = p[2] - cur[2];  const sq = dx * dx + dy * dy + dz * dz; // 최대 약 8×10^12: 2^53 안이라 정확하다  total += Math.sqrt(sq);  out.push(total.toFixed(2));  if (sq > bestSq) {    best = i + 1;    bestSq = sq;  }  cur = p;});out.push(best);console.log(out.join("\n"));
TypeScriptmain.ts · 28 行
import { readFileSync } from "node:fs";const nums: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const n = nums[0];type Point = [number, number, number];const points: Point[] = [];for (let i = 0; i < n; i++) points.push([nums[1 + 3 * i], nums[2 + 3 * i], nums[3 + 3 * i]]);points.push([0, 0, 0]); // 마지막 구간은 기지로 돌아오는 길 let cur: Point = [0, 0, 0];let total = 0;let best = 1;let bestSq = -1;const out: string[] = [];points.forEach((p, i) => {  const dx = p[0] - cur[0];  const dy = p[1] - cur[1];  const dz = p[2] - cur[2];  const sq = dx * dx + dy * dy + dz * dz; // 최대 약 8×10^12: 2^53 안이라 정확하다  total += Math.sqrt(sq);  out.push(total.toFixed(2));  if (sq > bestSq) {    best = i + 1;    bestSq = sq;  }  cur = p;});out.push(String(best));console.log(out.join("\n"));
JavaMain.java · 36 行
import java.util.Locale;import java.util.Scanner; public class Main {    public static void main(String[] args) {        Scanner sc = new Scanner(System.in);        int n = sc.nextInt();        long cx = 0, cy = 0, cz = 0;        double total = 0;        int best = 1;        long bestSq = -1;        StringBuilder out = new StringBuilder();        for (int i = 1; i <= n + 1; i++) {            // 마지막(n + 1번째) 구간은 기지 (0, 0, 0)으로 돌아오는 길            long x = 0, y = 0, z = 0;            if (i <= n) {                x = sc.nextLong();                y = sc.nextLong();                z = sc.nextLong();            }            long dx = x - cx, dy = y - cy, dz = z - cz;            long sq = dx * dx + dy * dy + dz * dz; // 차이가 2×10^6이면 제곱은 4×10^12: long이 필요하다            total += Math.sqrt(sq);            out.append(String.format(Locale.ROOT, "%.2f", total)).append('\n');            if (sq > bestSq) {                best = i;                bestSq = sq;            }            cx = x;            cy = y;            cz = z;        }        out.append(best).append('\n');        System.out.print(out);    }}
C#Main.cs · 42 行
using System;using System.Globalization;using System.Text; class Program{    static void Main()    {        int n = int.Parse(Console.ReadLine());        long cx = 0, cy = 0, cz = 0;        double total = 0;        int best = 1;        long bestSq = -1;        var out_ = new StringBuilder();        for (int i = 1; i <= n + 1; i++)        {            // 마지막(n + 1번째) 구간은 기지 (0, 0, 0)으로 돌아오는 길            long x = 0, y = 0, z = 0;            if (i <= n)            {                string[] p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);                x = long.Parse(p[0]);                y = long.Parse(p[1]);                z = long.Parse(p[2]);            }            long dx = x - cx, dy = y - cy, dz = z - cz;            long sq = dx * dx + dy * dy + dz * dz; // 차이가 2×10^6이면 제곱은 4×10^12: long이 필요하다            total += Math.Sqrt(sq);            out_.Append(total.ToString("F2", CultureInfo.InvariantCulture)).Append('\n');            if (sq > bestSq)            {                best = i;                bestSq = sq;            }            cx = x;            cy = y;            cz = z;        }        out_.Append(best).Append('\n');        Console.Write(out_);    }}
C++main.cpp · 29 行
#include <cmath>#include <cstdio>#include <iostream> int main() {    int n;    std::cin >> n;    long long cx = 0, cy = 0, cz = 0;    double total = 0;    int best = 1;    long long bestSq = -1;    for (int i = 1; i <= n + 1; i++) {        // 마지막(n + 1번째) 구간은 기지 (0, 0, 0)으로 돌아오는 길        long long x = 0, y = 0, z = 0;        if (i <= n) std::cin >> x >> y >> z;        long long dx = x - cx, dy = y - cy, dz = z - cz;        long long sq = dx * dx + dy * dy + dz * dz; // 제곱은 4×10^12까지: long long        total += std::sqrt(static_cast<double>(sq));        std::printf("%.2f\n", total);        if (sq > bestSq) {            best = i;            bestSq = sq;        }        cx = x;        cy = y;        cz = z;    }    std::printf("%d\n", best);}
Cmain.c · 29 行
#include <math.h>#include <stdio.h> int main(void) {    int n;    scanf("%d", &n);    long long cx = 0, cy = 0, cz = 0;    double total = 0; /* float는 일곱 자리쯤에서 끝나 소수 둘째 자리를 지킬 수 없다 */    int best = 1;    long long best_sq = -1;    for (int i = 1; i <= n + 1; i++) {        /* 마지막(n + 1번째) 구간은 기지 (0, 0, 0)으로 돌아오는 길 */        long long x = 0, y = 0, z = 0;        if (i <= n) scanf("%lld %lld %lld", &x, &y, &z);        long long dx = x - cx, dy = y - cy, dz = z - cz;        long long sq = dx * dx + dy * dy + dz * dz; /* 제곱은 4×10^12까지: long long */        total += sqrt((double)sq);        printf("%.2f\n", total);        if (sq > best_sq) {            best = i;            best_sq = sq;        }        cx = x;        cy = y;        cz = z;    }    printf("%d\n", best);    return 0;}
Craykonmain.cray · 31 行
n = 控制台.读行().转数字();cx = 0;cy = 0;cz = 0;total = 0;best = 1;bestSq = -1;循环 (i = 1; i <= n + 1; i++){    // 마지막(n + 1번째) 구간은 기지 (0, 0, 0)으로 돌아오는 길    p = [0, 0, 0];    如果 (i <= n)    {        p = 控制台.读数字();    }    dx = p[0] - cx;    dy = p[1] - cy;    dz = p[2] - cz;    sq = dx * dx + dy * dy + dz * dz; // 최대 약 8×10^12: 2^53 안이라 정확하다    total += 数学.平方根(sq);    控制台.输出(字符.保留小数(total, 2));    如果 (sq > bestSq)    {        best = i;        bestSq = sq;    }    cx = p[0];    cy = p[1];    cz = p[2];}控制台.输出(best);