数学女孩2--费马大定理
第一章 将无限宇宙尽收掌心
时钟巡回 之 完全巡回的规律
问题描述: 将圆12 等分, 12个点分别标记为【1...12】。 从12点开始每隔 k 个点连一条线。如果 k == 1, 则第一条连线是(12, 2)。完全巡回的定义是 选定某个K, 重复连线的过程,最终圆上所有点都被连接。
进一步的抽象: 另 F(x) = (x + k) mod 12, k > 0, 初始状态下定义域中仅有一个元素即起点, 每次计算完毕都有 x = F(x); 即定义域中始终只有一个值,若 F(x) 的值域为所有的顶点的标号, 则称为完全巡回。 用代码描述如下:(在最后面)
更进一步的思考:
在连线的时候有顺时针和逆时针的区别, K 取 11 和 1 时,就是逆时针和顺时针将12个点相连。而 11 + 1 ==12。 若 a + b == 12, 则 k 取 a 和 k 取 b 效果是一样的。 (逆时针查 7 个点是5, 顺时针查 5 个点还是 5) 由此可将问题的求解范围缩小一半(只需考虑 k 取【1...6】即可)。 若 K 取 2 3 4 6, F(x) 总是一倍一倍的增上去...
最后我的答案:
对于 K【1...11】;
k = k<=6 ? k : 12-k;
if( 12 % k || k == 1 )
return true;
return false;
书上的解:
m 是圆上点数
if(gcd (m, k) == 1)
return true;
return false;
//////////////////////////////////////////////////////////////
#include <iostream>
#include <cstring>
using namespace std;
#define MAXN 13
int ans[MAXN], from, to, i, j; // ans[MAXN] 存放值域
int main(){
for(i=1; i<=11; ++i){ //由于取余运算中会有 0 的出现, 所以标号化为【0...11】
from = 11;
to = 0;
memset(ans, 0, sizeof(ans));
while(to != 11){ // 可以肯定最终一定会回到 最初的起点
to = (from + i) % 12;
from = to;
ans[to] = 1;
}
for(j=0; j<=11; ++j)
if(ans[j] == 0)
break;
if(j==12)
cout << " " << i;
}
return 0;
}
//////////////////////////////////////////////////////////////