题目:把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