1.问题简介:给你一个三角形里面是successive integer(连续的整数)。要求只能通过边来从一个元素访问另一个元素,求从点M到点N的最短路径(即从M开始最短通过几条边到达N)。
2.问题分析:
为了更方便的分析,我画了一张图来看里面的结构,即只能通过边来访问。(发现这个图很美,有点像蜂巢的六边形,不断延续下去)。最开始我是想通过dijkstra最短路访问,最后发现构图是个问题,而且最短路需要O(n²),所以换别的思路。看了原来大神的思路,才明白一些。
从3号到12号需要5个步骤,3种动作,只要求出3种动作每个有多少步,然后加起来即是最短步骤。
3.具体分析:
(参考博主https://www.cnblogs.com/ACMan/archive/2012/05/30/2526798.html)
我们规定 : 计算从m点到n点的最短距离。cm 是m的行数,cn 是n的行数。
(如计算点6到点12,m为6,n为12,cm = 3,cn = 4)。
①。计算中间图2层之间差值:
cm = (int)ceil(sqrt(m)); /*ceil是math.h中的函数,代表(取上界)*/
cn = (int)ceil(sqrt(n));
②。计算左划图2层之间差值:
我们规定: lm 是m左移层数,ln 是n左移层数。
lm = (int)ceil( (m-(cm-1)*(cm-1))/2.0 );
ln = (int)ceil( (n-(cn-1)*(cn-1))/2.0 );
③。计算右移之间差值:
我们规定: rm 是m右移层数,rn 是n右移层数。
rm = (int)ceil( (cm*cm-m+1)/2.0 );
rn = (int)ceil( (cn*cn-n+1)/2.0 );
4.详细代码:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int m,n,cm,cn,lm,ln,rm,rn;
while(cin >> m >> n)
{
cm = (int)ceil(sqrt(m));
cn = (int)ceil(sqrt(n));
lm = (int)ceil( (m-(cm-1)*(cm-1))/2.0 );
ln = (int)ceil( (n-(cn-1)*(cn-1))/2.0 );
rm = (int)ceil( (cm*cm-m+1)/2.0 );
rn = (int)ceil( (cn*cn-n+1)/2.0 );
cout << (int)(fabs(cm-cn)+fabs(lm-ln)+fabs(rm-rn)) << endl;
}
return 0;
}
5.Note:
1.有些同学可能个别解是对的,个别是错的。没错我也遇到了,最后debug了一下,发现是把2改成2.0就对了。
比如1/2取上界是0,因为1/2赋值给int值是0,而1/2.0结果为float型,可以保存。
2.还有一个问题是:
①。ceil函数,他的原型是:(所以最后结果可以(int)一下子,使他结果为整数。)
double ceil( double x)
{
return 大于等于x的整数。
}
②。floor函数,他的原型与ceil类似,返回的是小于等于x的最大的整数。