素数环
把整数1,2,3...n组成一个环, 相邻两环之和为素数, 每种环输出一次.
1. 穷举所有排列. 排列总数为n!个.当n取17时, 运算结果如下:
total: 0. with running time: 3.994225 sec.
已经有些吃力了Orz...
(代码有点啰嗦, 这里可以直接使用next_permutation()来实现)
额..后来发现这个属于回溯.
#define S 17 int total = 0; int N[S] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17}; int C[S] = {0}; bool isPrime(int n) { for ( int i = 2; i < n; i++) if ( n%i == 0 ) return false; return true; } void subset(int n, int *a, int cur) { if ( n == cur ) { //for ( int i = 0; i < n; i++ ) printf("%d ", C[i]); printf("\n"); total ++; return; } for ( int i = 0; i < n; i++ ) { int ok = 1; for ( int j = 0; j < cur; j++ ) { if ( C[j] == N[i] ) { ok = 0; break; } } if ( !ok ) continue; if ( cur ) if ( !isPrime( C[cur - 1] + N[i]) ) ok = 0; if ( cur == n - 1 ) if ( !isPrime( C[0] + N[i]) ) ok = 0; if ( ok ) { C[cur] = N[i]; subset(n, a, cur + 1); } } } int main() { C[0] = 1; clock_t t0 = clock(); subset(S, C, 1); clock_t t1 = clock(); printf("total: %d. with running time: %f sec.\n", total, ((float)(t1-t0))/CLOCKS_PER_SEC); return 0; }
使用STL的版本:
代码少了很多, 但这个版本n>12就算不出来了Orz..
int main() { int n = S; int isp[S*2+1] = {0}; int A[S]; for ( int i = 2; i < S*2; i++ ) isp[i] = isPrime(i); clock_t t0 = clock(); for ( int i = 0; i < n; i++ ) A[i] = i+1; do { int ok = 1; for ( int i = 0; i < n; i++ ) if ( !isp[A[i]+A[(i+1)%n]] ) { ok = 0; break;} if ( ok ) { total ++; } } while (next_permutation(A+1, A+n)); clock_t t1 = clock(); printf("total: %d. with running time: %f sec.\n", total, ((float)(t1-t0))/CLOCKS_PER_SEC); return 0; }
2. 回溯法.
这是最快的版本. n=16只需0.1s.
注意素数要用素数表保存.
void dfs(int cur) { if ( n == cur && isPrime(C[0] + C[n-1])) { total++; return; } for ( int i = 2; i <= n; i++ ) { if ( !vis[i] && isp[i+C[cur-1]] ) { vis[i] = 1; C[cur] = i; dfs(cur + 1); vis[i] = 0; // 重要! 清除标志. } } } int main() { for ( int i = 2; i < S*2; i++ ) isp[i] = isPrime(i); C[0] = 1; vis[1] = 1; dfs(1);
return 0; }