首页 > 代码库 > UVa 524 - Prime Ring Problem

UVa 524 - Prime Ring Problem

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