蓝桥杯:螺旋折线 模拟解法

如图所示的螺旋折线经过平面上所有整点恰好一次。

对于整点(X, Y),我们定义它到原点的距离dis(X, Y)是从原点到(X, Y)的螺旋折线段的长度。
例如dis(0, 1)=3, dis(-2, -1)=9

给出整点坐标(X, Y),你能计算出dis(X, Y)吗?
在这里插入图片描述

思路

感觉这就是个模拟题,我们可以抓大放小

总体思路:
先走足够多次,到能够满足其中一个目标坐标的位置,再根据当前位置和目标点的差距,补偿步数即可

1.走到满足一个坐标:

如下图,可以看到都是两步两步地走的,即:走两次,变换步长,再走(不同颜色表示不同步长)

约定:以相同的步长走两步,为走一次
例:到点(2, -2)走了4次

在这里插入图片描述

并且可以发现,对于x或y,想要到达目标坐标值,走的次数可以由目标坐标值确定
在这里插入图片描述

对于x轴,想要达到x坐标:
如果x为负数,那么次数就是 -x*2 - 1
如果x为正数,那么次数就是 2*x

对于y轴,想要达到y坐标:
如果y为负数,那么次数就是 -x*2
如果y为正数,那么次数就是 2*x - 1

我们取目标x,y之中,需要走次数最大的,作为我们走的次数time (因为要保证两个轴都能够道达)

走的次数和距离满足等差数列前n项和
次数 time:1,2,3,4
距离 dis :2,6,12,20

dis = (time + 1) * time

2.补偿步数:

如果按照上述思路,有可能会走过头,或者是走不够

这时候需要根据黑点的坐标,补偿步数,走过了就减,没走到就加

为了达到x=-2,我们走了三次,到达黑点,目标是黄点,显然走过了
在这里插入图片描述

为了到达y=2,我们走了3次,到达黑点,目标是黄点,显然走的不够多
在这里插入图片描述

代码

多组数据测试的运行结果:
在这里插入图片描述

#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

#define iabs(x) ((int)fabs(x))
typedef long long ll;
int X, Y, x, y;

int main()
{
	cin>>X>>Y
	if(X==0 && Y==0)
	{
		cout<<"dis=0"<<endl;
		continue;
	}

	ll sum = 0;		// 步数和 
	int time = 0;	// 走的次数 
	// 计算最少次数 
	if(X > 0)
	{
		time = max(time, 2*X);
	}
	else
	{
		time = max(time, 2*iabs(X) - 1);
	}
	if(Y > 0)
	{
		time = max(time, 2*Y - 1);
	}
	else 
	{
		time = max(time, 2*iabs(Y));
	}
	
	// 计算步数(等差数列求和) 
	sum = time * (time+1);
	// 计算走time次之后的最终坐标(规律同上面那个图)
	if(time%2 == 0)
	{
		x = time/2;
		y = -1*time/2;
	}
	else
	{
		x = -1*(time+1)/2;
		y = (time+1)/2;
	}
	
	// 步数补偿:如果点不在整步数点上,分类讨论 
	if(x==X && y==Y)
	{
		cout<<"dis="<<sum<<endl;
	}
	// x到了y没到
	else if(x==X && y!=Y)
	{
		// x > 0,表示正在往下走 
		if(x > 0)
		{
			sum += y - Y;
		}
		// x < 0 表示正在往上走 
		else
		{
			sum -= y - Y;
		}
		cout<<"dis="<<sum<<endl;
	}
	// x没到y到了
	else if(x!=X && y==Y)
	{
		// y > 0 表示正在往右走 
		if(y > 0)
		{
			sum -= x - X;
		}
		//  y < 0 表示正在往左走 
		else
		{
			sum += x - X;
		}
		cout<<"dis="<<sum<<endl;
	}
	
	return 0;
}

递增的测试样例

0 0
-1 0
-1 1
0 1
1 1
1 0
1 -1
0 -1
-1 -1
-2 -1
-2 0
-2 1
-2 2
-1 2
0 2
1 2
2 2
2 1
2 0
2 -1
2 -2
1 -2
0 -2
-1 -2
-2 -2
-3 -2
-3 -1
-3 0
-3 1
-3 2
-3 3
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值