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