题目:把1-n,连续的放到一个环里,使相邻的数字和为素数,输出所有结果。
分析:搜索+剪枝。如果裸搜,用dancing-links那种拆装的链表,应该差不多满足16的数据量。
这里利用一个性质进行剪枝:相邻的数字一定是奇偶性不同的数字。
(如果上述假设不成立,则存在相邻的奇数或偶数,那么他们的和一定是大于2的偶数,不是素数)
根据上面的假设,还有一条推论:只有n为偶数时才有解。
(n为奇数,一直至少有一对奇数相邻,同上,矛盾(鸽巢原理))
因此,每次搜索的数据其实是n/2,时间复杂度为O((n/2)!* 2^(n/2));
打表计算,查询输出即可。
说明:注意题目没说,每组输出间有一个空行。
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
using namespace std;
int prime[32];
int visit[18];
int queue[18];
int size[18];
int ans[18][100000][18];
void dfs( int d, int n )
{
if ( d == n && !prime[queue[d-1]+1] ) {
for ( int i = 1 ; i < n ; ++ i )
ans[n][size[n]][i] = queue[i];
size[n] ++;
return;
}
for ( int i = d%2+1; i <= n ; i += 2 )
if ( !visit[i] && !prime[i+queue[d-1]] ) {
visit[i] = 1;
queue[d] = i;
dfs( d+1, n );
visit[i] = 0;
}
}
int main()
{
memset( prime, 0, sizeof(prime) );
prime[0] = prime[1] = 1;
for ( int i = 2 ; i < 32 ; ++ i )
if ( !prime[i] )
for ( int j = 2*i ; j < 32 ; j += i )
prime[j] = 1;
memset( visit, 0, sizeof(visit) );
visit[1] = 1;
queue[0] = 1;
memset( size, 0, sizeof(size) );
for ( int i = 2 ; i <= 16 ; i += 2 )
dfs( 1, i );
int n,m,t = 0;
while ( ~scanf("%d",&n) ) {
if ( t ++ ) printf("\n");
printf("Case %d:\n",t);
m = size[n];
for ( int i = 0 ; i < m ; ++ i ) {
printf("1");
for ( int j = 1 ; j < n ; ++ j )
printf(" %d",ans[n][i][j]);
printf("\n");
}
}
return 0;
}