《算法竞赛·快冲300题》每日一题:“立方体表面距离”

算法竞赛·快冲300题》将于2024年出版,是《算法竞赛》的辅助练习册。
所有题目放在自建的OJ New Online Judge
用C/C++、Java、Python三种语言给出代码,以中低档题为主,适合入门、进阶。


立方体表面距离” ,链接: http://oj.ecustacm.cn/problem.php?id=1139

题目描述

【题目描述】 给定一个立方体,长宽高分别为L,W,H,以立方体一顶点建立空间直角坐标系。有两点A(x1, y1, z1)和B(x2, y2, z2)位于立方体表面上。求两点在立方体表面上的最短距离的平方。
在这里插入图片描述

【输入格式】 输入有多组数据,输入数字依次为L,W,H,x1,y1,z1,x2,y2,z2。0≤L,W,H≤1000,0≤x≤L,0≤y≤W,0≤z≤H。输入保证A、B两点在立方体表面上。
【输出格式】 对于每组数据,输出一行,包含最短距离,答案精确到小数点后0位。
【输入样例】

5 5 2 3 1 2 3 5 0

【输出样例】

36

题解

   如果两点在同一面上,最短距离是它们在平面上的连线。如果两点在不同的两个面上,可以想象立方体是一个纸盒子,把纸盒子展开成一个平面,两点的最短距离是这个平面上的连线。
   本题的重点是立方体展开过程中的坐标变换,读者可以自己设计一种展开方法。
   下面介绍代码中的展开方法,分两个步骤。
   步骤(1)。为方便处理A、B点的关系,把A点移动到底面上,也就是z=0的面。以下图为例,A在y=W的面上,把立方体沿x轴整体右旋90度,那么A点就到了底面上。
在这里插入图片描述
   步骤(2)。把A、B所在的面都展开或旋转到底面上,这样A、B就位于同一个面上。以下图为例,A在底面上,B在y=W的面上。先把立方体沿着x轴右旋90度,B就到了底面上。A原来在底面,现在向左平移W(或者看成从中间图的左侧面向左下展开到底面)。这时A、B都位于底面上。
在这里插入图片描述

【重点】

C++代码

   代码19~34行完成步骤(1),把A点转到底面上。
   函数getAns()完成步骤(2),把A、B所在的面展开到同一个面,然后计算距离。参数i表示绕y轴旋转,参数j表示绕x轴旋转。i和j只变化两次,对应立方体旋转1次或2次。例如第12行“右旋,绕x轴转1~2次”,是上图图示的情况,B在侧面,只转1次就到底面;如果B在z = H的顶面,就需要转2次才能转到底面。

#include<bits/stdc++.h>
using namespace std;
const double INF = 1e20;
double length2(double x1, double y1, double x2, double y2){
    return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1);
}
double ans;
void getAns(int i,int j,double x,double y,double x2,double y2,double z2,double L,double W,double H){
if( z2==0 && ans>length2(x,y,x2,y2 ))   ans=length2(x,y,x2,y2 ); //AB在同一个面,计算距离
    if( i>= 0 && i< 2 )  getAns(i+1,j,x+H,y,H-z2,y2,x2,H,W,L);   //后旋,绕y轴转1~2次
    if( i<= 0 && i> -2)  getAns(i-1,j,x-L,y,z2,y2,L-x2,H,W,L);   //前旋,绕y轴转1~2次
    if( j>= 0 && j< 2 )  getAns(i,j+1,x,y-W,x2,z2,W-y2,L,H,W);   //右旋,绕x轴转1~2次
    if( j<= 0 && j> -2)  getAns(i,j-1,x,y+H,x2,H-z2,y2,L,H,W);   //左旋,绕x轴转1~2次
}
int main(){
    double L, W, H;
    double x1, y1, z1, x2, y2, z2;
    while(cin>>L>>W>>H>>x1>>y1>>z1>>x2>>y2>>z2){
        if( z1!=0 && z1!=H){          //A点不在Z=0或Z=H的面上
            if( x1!=0 && x1!=L ){     //A也不在x面上,那么A在y面上
                swap(y1, z1);         //把立方体绕x轴旋转,把A点转到了z面
                swap(y2, z2);
                swap(W, H);
            }
            else {                    //A在x的面上
                swap(x1, z1);         //把立方体绕y轴旋转,把A点转到z面
                swap(x2, z2);
                swap(L, H);
            }
        }
        if( z1==H ){                  //把A点调整到z=0,即底面
            z1 = 0;
            z2 = H-z2;
        }
        ans=INF;
        getAns(0, 0, x1, y1, x2, y2, z2, L, W, H );  //z1=0, A点在z=0的面上。求AB的最短距离
        cout<<(int)round(ans)<<endl;
    }
    return 0;
}

Java代码

import java.util.Scanner;
public class Main {
    private static final double INF = 1e20;
    private static double length2(double x1, double y1, double x2, double y2) {
        return (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
    }
    private static double ans;
    private static void getAns(int i,int j,double x,double y,double x2,double y2,double z2,double L, double W, double H) {
        if (z2 == 0 && ans > length2(x, y, x2, y2))    ans = length2(x, y, x2, y2);
        if (i >= 0 && i < 2)   getAns(i + 1, j, x + H, y, H - z2, y2, x2, H, W, L);        
        if (i <= 0 && i > -2)  getAns(i - 1, j, x - L, y, z2, y2, L - x2, H, W, L);
        if (j >= 0 && j < 2)   getAns(i, j + 1, x, y - W, x2, z2, W - y2, L, H, W);
        if (j <= 0 && j > -2)  getAns(i, j - 1, x, y + H, x2, H - z2, y2, L, H, W);
    }
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            double L = scanner.nextDouble();
            double W = scanner.nextDouble();
            double H = scanner.nextDouble();
            double x1 = scanner.nextDouble();
            double y1 = scanner.nextDouble();
            double z1 = scanner.nextDouble();
            double x2 = scanner.nextDouble();
            double y2 = scanner.nextDouble();
            double z2 = scanner.nextDouble();
            if (z1 != 0 && z1 != H) {
                if (x1 != 0 && x1 != L) {
                    double temp = y1; y1 = z1;  z1 = temp;    
                    temp = y2;  y2 = z2;  z2 = temp;    
                    temp = W;   W = H;    H = temp;
                } else {
                    double temp = x1;  x1 = z1;   z1 = temp;
                    temp = x2;   x2 = z2;    z2 = temp;
                    temp = L;    L = H;      H = temp;
                }
            }
            if (z1 == H) {
                z1 = 0;
                z2 = H - z2;
            }
            ans = INF;
            getAns(0, 0, x1, y1, x2, y2, z2, L, W, H);
            System.out.println((int) Math.round(ans));
        }
        scanner.close();
    }
}

Python代码

import math
INF = 1e20
def length2(x1, y1, x2, y2):   return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)
def getAns(i, j, x, y, x2, y2, z2, L, W, H):
    global ans
    if z2==0 and ans>length2(x, y, x2, y2):    ans=length2(x, y, x2, y2)
    if i>= 0 and i< 2:     getAns(i+1, j, x+H, y, H-z2, y2, x2, H, W, L)
    if i<= 0 and i> -2:    getAns(i-1, j, x-L, y, z2, y2, L-x2, H, W, L)
    if j>= 0 and j< 2:     getAns(i, j+1, x, y-W, x2, z2, W-y2, L, H, W)
    if j<= 0 and j> -2:    getAns(i, j-1, x, y+H, x2, H-z2, y2, L, H, W)
  
while True:
    try:
        L, W, H, x1, y1, z1, x2, y2, z2 = map(float, input().split())
        if z1!=0 and z1!=H:
            if x1!=0 and x1!=L:
                y1, z1 = z1, y1
                y2, z2 = z2, y2
                W, H = H, W
            else:
                x1, z1 = z1, x1
                x2, z2 = z2, x2
                L, H = H, L
        if z1==H:
            z1=0
            z2=H-z2
        ans = math.inf
        getAns(0, 0, x1, y1, x2, y2, z2, L, W, H)
        print(round(ans))
    except EOFError:
        break
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

罗勇军

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值