如下数列,第一项是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\n", s-n+1, k-s+n); //表示输出第k斜线倒数第s-n+1项 14 else printf("%d/%d\n", 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 }
分析:
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\n", s-n+1, k-s+n); //表示输出第k斜线倒数第s-n+1项 11 else printf("%d/%d\n", k-s+n, s-n+1); //表示输出第k斜线正数第k-(s-n+1)+1项,即k-s+n项 12 } 13 return 0; 14 }
分析:
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\n", k+1-n, n); //表示输出第k斜线倒数第(k-n)+1项 14 else printf("%d/%d\n", n, k+1-n); //表示输出第k斜线正数第n项 15 } 16 return 0; 17 }
分析:
用n减去前k条斜线上的个数后再和第k条斜线上个数相比即得所求数位置。