题目:把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; }
UVa 524 - Prime Ring Problem,布布扣,bubuko.com
原文地址:http://blog.csdn.net/mobius_strip/article/details/36624421