Hoodlum1980 (fafa)'s Technological Blog

Languages mainly using and digging: C / CPP, ASM, C#, Python. Other languages:Java.

博客园 首页 新随笔 联系 订阅 管理

    ZOJ 1871: Steps

    地址:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=871

    题意:假设在一条直线上标记着数字刻度。每一步的步长不能为负数,且和前一个步长的关系必须是相等,或大于或小于1。第一步和最后一步的步长必须是1。则从 x 到 y 的最小步数是多少。

 

    可以用数学语言重新描述题目如下:给出无符号整数 d ( =  y-x ) ,可分解为满足下列条件的 n 个正整数的和,求 n 的最小值:

     d = ∑ Si ; (i = 1 ... n)

   

    且满足:

    S1 = Sn = 1;

    | S(i + 1) - Si | ≤ 1;

 

    分析:根据题目要求,理想条件下,为了达到最小步数,步长变化应该是从1,2,3 ... 一直增加到最大值 M,然后逐渐减小到1:

    distance = y - x ;

    distance = 1 + 2 + 3 + ... + M + ... + 3 + 2 + 1 = M^2;

    steps = 2 * M - 1;  (步数)

    

    因此如果距离正好是一个平方数(M 的平方),则步数一定是(2M-1),其中 M 为 最大步长。当距离不是平方数时,假设介于 M^2 和 (M+1)^2 之间,则

    distance = M^2 + remain; (0 < remain <= 2M )

    

    remain 是平方数后的尾数,如果remain 小于等于 M,则我们只需要把一个 remain 的步长插入到前面的序列中即可。如果 remain 大于 M,则一步是不够的,我们至少需要插入两步,M 和 remain - M(当然,也可以是 remain/2 和 remain - remain/2)。因为我们不能插入大于 M 的步长,否则最终累加的和会达到下一个平方数((M+1)的平方)。

 

    因此根据上述分析,代码如下(代码中为了可读性,M 用 maxStep 表示):

code_zoj1871
#include <stdio.h>
#include <math.h>
int main(int argc, char* argv[])
{
    unsigned int x = 0, y = 0;
    unsigned int distance, maxStep, remain, steps;
    while(scanf("%lu %lu", &x, &y) != EOF)
    {
        distance = y - x;
        if(distance == 0)
        {
            printf("0\n");
            continue;
        }
        maxStep = (unsigned int)sqrt(distance);
        remain = distance - maxStep * maxStep;

        steps = maxStep * 2 - 1;
        if(remain > 0)
        {
            if(remain <= maxStep)
                steps++;
            else
                steps += 2;
        }
        printf("%lu\n", steps);
    }
    return 0;
}

 

 

posted on 2012-05-28 11:30  hoodlum1980  阅读(422)  评论(0编辑  收藏  举报