• 《算法竞赛入门经典》5.41数学基础-Cantor的数表


    如下数列,第一项是1/1,第二项是1/2,第三项是2/1,第四项是3/1,第五项是2/2,……。输入n,输出第n项。
    1/1   1/2   1/3   1/4   1/5
    2/1   2/2   2/3   2/4
    3/1   3/2   3/3
    4/1   4/2
    5/1
    样例输入:
    3
    14
    7
    12345
    样例输出:
    2/1
    2/4
    1/4
    59/99

    方法一:

     1 #include <stdio.h>
     2 int main()
     3 {
     4     int n;
     5     while(scanf("%d", &n) == 1)
     6     {
     7         int k = 1, s = 0;
     8         for(; ; )
     9         {
    10             s += k;
    11             if(s >= n)    //s为k条斜线上数的总和
    12             {
    13                 if(k%2 == 1)    printf("%d/%d
    ", s-n+1, k-s+n); //表示输出第k斜线倒数第s-n+1项
    14                 else            printf("%d/%d
    ", k-s+n, s-n+1); //表示输出第k斜线正数第k-(s-n+1)+1项,即k-s+n项
    15                 break;
    16             }
    17             k++;
    18         }
    19     }
    20     return 0;
    21 }
    View Code

    分析:
      1.数表按斜线分类,第1条斜线有1个数,第2条斜线有2个数……第i条斜线有i个数,这样,前i条斜线一共有S(k)=1+2+3+…+k=k(k+1)/2个数;并且是一条斜线从上到下,另一条斜线从下到上交错排数。
      2.确定n所在斜线:只要找到一个最小的正整数k,使得n<=S(k),那么n就是第k条斜线上的倒数第S(k)-n+1个元素(最后一个元素是倒数第一个元素,而不是倒数第零个元素);则第k条斜线的倒数(k为奇数时,第k斜线倒序)第i个元素是i/(k+1-i),正数(k为偶数时,第k斜线正序)第i个元素是(k+1-i)/i。

    方法二:

     1 #include <stdio.h>
     2 #include <math.h>
     3 int main()
     4 {
     5     int n;
     6     while(scanf("%d", &n))
     7     {
     8         int k = (int)floor((sqrt(8.0*n+1)-1) / 2-1e-9) + 1;    //使用floor函数避免浮点误差
     9         int s = k*(k+1) / 2;    //s为k条斜线上数的总和
    10         if(k%2 == 1)    printf("%d/%d
    ", s-n+1, k-s+n);    //表示输出第k斜线倒数第s-n+1项
    11         else            printf("%d/%d
    ", k-s+n, s-n+1);    //表示输出第k斜线正数第k-(s-n+1)+1项,即k-s+n项
    12     }
    13     return 0;
    14 }
    View Code

    分析:
      1.利用代数,n<=k*(k+1)/2,k*k+k-2n>=0,(k-(sqrt(8.0*n+1)-1)/2)*(k-(-sqrt(8.0*n+1)-1)/2)>=0,注意到k-(-sqrt(8.0*n+1)-1)/2总是正数,则k>=(sqrt(8.0*n+1)-1)/2;换言之,可以直接求出则k=(sqrt(8.0*n+1)-1)/2。
      2.floor()函数,其功能是“向下取整”,或者说“向下舍入”,即取不大于x的最大整数(与“四舍五入”不同,下取整是直接去掉小数部分);
      3.指数形式:由于计算机输入或输出时,无法表示上角或下角,规定以字母e或E代表以10为底的指数;注意:e或E之前必须有数字,e或E后面必须是带符号的十进制整数,长度最大为3位,正数时可不写+号。

    方法三:

     1 #include <stdio.h>
     2 int main()
     3 {
     4     int n;
     5     while (scanf("%d", &n) == 1)
     6     {
     7         int k = 1;
     8         while (k < n)    //k为第n项所在行数,循环的意义为所求数在第k条斜线第n项
     9         {
    10             n -= k;        //n减去第k条斜线上的数
    11             k++;
    12         }
    13         if (k%2 == 1)    printf("%d/%d
    ", k+1-n, n); //表示输出第k斜线倒数第(k-n)+1项
    14         else            printf("%d/%d
    ", n, k+1-n); //表示输出第k斜线正数第n项
    15     }
    16     return 0;
    17 }
    View Code

    分析:

      用n减去前k条斜线上的个数后再和第k条斜线上个数相比即得所求数位置。

    亲爱的读者:如果觉得本文对你有所帮助,请点击推荐,分享给其他人!
  • 相关阅读:
    C# 窗体间传值方法大汇总(转)
    STM32 配置PC13~PC15
    STM32的USART发送数据时如何使用TXE和TC标志
    STM32_NVIC寄存器详解
    protel99se 问题汇总(不定期更新)
    STM32串口IAP实验笔记
    Keil MDK下如何设置非零初始化变量(复位后变量值不丢失)
    STM32定时器配置(TIM1-TIM8)高级定时器+普通定时器,定时计数模式下总结
    帮助类-AD域操作
    GitHub贡献第一的公司是谁?微软开源软件列表
  • 原文地址:https://www.cnblogs.com/zhuangwei/p/5330432.html
Copyright © 2020-2023  润新知