杭电oj HDOJ 2073 无限的路
题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2073
Problem Description
甜甜从小就喜欢画图画,最近他买了一支智能画笔,由于刚刚接触,所以甜甜只会用它来画直线,于是他就在平面直角坐标系中画出如下的图形:
甜甜的好朋友蜜蜜发现上面的图还是有点规则的,于是他问甜甜:在你画的图中,我给你两个点,请你算一算连接两点的折线长度(即沿折线走的路线长度)吧。
Input
第一个数是正整数N(≤100)。代表数据的组数。
每组数据由四个非负整数组成x1,y1,x2,y2;所有的数都不会大于100。
Output
对于每组数据,输出两点(x1,y1),(x2,y2)之间的折线距离。注意输出结果精确到小数点后3位。
解题思路
分别算出从原点到(x1,y1)和(x2,y2)的距离,二者之差的绝对值则是所求的两点之间的折线距离。那么怎么计算原点到所求点的距离呢?
设一个模拟点,一步步地模拟累加从原点出发所走的距离,如果模拟点与所求点重合,此时距离累加的结果就是原点到所求点的距离。
除了(0,0)和(1,0)两个特殊点, 其他都是从“横坐标为0”的点向右下移动,直到纵坐标为0,再回到下一个“横坐标为0”的点继续右下移动,无限循环。其中每一步“右下移动”所走的距离为
2
\sqrt{2}
2。并且如果此时的模拟点坐标为(x,0),则下一个“横坐标为0”的点为(0,x+1),期间所走的距离为
x
2
+
(
x
+
1
)
2
\sqrt{x^2+(x+1)^2}
x2+(x+1)2
本人的C++解决方案
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
double dis(int, int); // 从起点到参数点所走的距离
int main()
{
int N, i, x1, y1, x2, y2;
double res_temp1, res_temp2, res;
cin >> N;
for (i = 0; i < N; i++) {
cin >> x1 >> y1 >> x2 >> y2;
res_temp1 = dis(x1, y1);
res_temp2 = dis(x2, y2);
res = abs(res_temp1 - res_temp2);
cout << setiosflags(ios::fixed) << setprecision(3) << res << endl;
}
return 0;
}
double dis(int a, int b)
{
// 记录模拟路线的坐标
int x, y;
// 记录每次从左上坐标到右下坐标所走“根号2”的个数
int count = 0;
double res;
// 初始化模拟路线的坐标,从原点开始
x = y = 0;
// 模拟路线的点与参数点重合,结算距离
if (a == x && b == y) {
res = 0;
}
else {
// 从原点走到(0, 1)
y++;
// 模拟路线的点与参数点重合,结算距离
if (a == x && b == y) {
res = 1;
}
else {
res = 1;
while (!x) {
// 从左上坐标到右下坐标每次横坐标加1,纵坐标减1
// 所以每次走的路程是一个“根号2”
while (y != 0) {
count++;
x++;
y--;
// 每次坐标改变都要检查模拟路线的点是否与参数点重合
if (a == x && b == y) {
break;
}
}
// 走到纵坐标为0时结算此过程走了几个“根号2”
res += count * sqrt(2.0);
// 把计数器清零
count = 0;
// 每次坐标改变都要检查模拟路线的点是否与参数点重合
if (a == x && b == y) {
break;
}
else {
// 再从右下坐标走到下一个左上坐标
res += sqrt(pow(x, 2.0) + pow(x + 1, 2.0));
y = x + 1;
x = 0;
// 检查模拟路线的点是否与参数点重合
if (a == x && b == y) {
break;
}
}
}
}
}
return res;
}
代码通过HDOJ平台运行检查,如发现错误,欢迎指出和纠正,谢谢!