原题地址https://www.luogu.com.cn/problem/P1014
现代数学的著名证明之一是Georg Cantor证明了有理数是可枚举的。他是用下面这一张表来证明这一命题的:
1/1, 1/2 , 1/31, 1/4, 1/5, …
2/1, 2/2 , 2/3, 2/4, …
3/1 , 3/2, 3/3, …
4/1, 4/2, …
5/1, …
… 我们以Z字形给上表的每一项编号。第一项是1/1,然后是1/2,2/1,3/1,2/2,…
输入格式 整数N(1≤N≤10000000)
输出格式 表中的第N项。
大体是这样:
(1)1/1 → (2)1/2 (6)1/3 → (7)1/4 (15)1/5, …
↙ ↗ ↙ ↗
(3)2/1, (5)2/2 (8)2/3 (14)2/4, …
↓ ↗ ↙ ↗
(4)3/1 (9)3/2 (13)3/3, …
↙ ↗
(10)4/1 (12)4/2, …
↓ ↗
(11)5/1, …
斜着看感觉像开封菜(kfc)里的冰激凌,一层层地堆上去
首先,设分子是a(初始值1),分母是b(初始值1),当前所在的序数为i(初始值为1,每次操作+1,直到加到所输数字N)。
int a=1,b=1,i=1;
int n; cin>>n; if(n==1) { cout<<"1/1";//特殊情况不用过多考虑 return 0; }
再看具体操作。不难发现,如果分子是1(第一行),那么标号的路径会在分母为偶数时转向左下方,分母为奇数时往前一步。
同理,分母是1时(第一列),那么标号的路径会在分子为偶数时转向右上方,分子为奇数时往下一步。
那么如果分子分母都不是1呢?这些分数可以归纳为向右上走和向左下走。这两种情况分别对应什么条件呢?
对!分子分母之和为偶数时向右上走,为奇数时向左下走!当分子分母有一个为1时(到达边界),那么再按分子、分母为1的情况处理。
代码如下:
#include<iostream> using namespace std; int a=1,b=1,i=1; int main() { int n; cin>>n; if(n==1) { cout<<"1/1"; return 0; } do { if((a+b)%2==0)//向右上走 { if(a!=1)//没到达边界 { a--;b++;//往右(b大1)上(a小1) } else//到达边界,往下走 { b++; } } else//向左下走 { if(b!=1)//没到达边界 { a++;b--;//往左(b小1)下(a大1) } else//到达边界,往前 { a++; } } i++; }while(i<n); cout<<a<<"/"<<b; return 0; }