HD_1016Prime Ring Problem(dfs)

Prime Ring Problem

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 36882    Accepted Submission(s): 16249


Problem Description
A ring is compose of n circles as shown in diagram. Put natural number 1, 2, ..., n into each circle separately, and the sum of numbers in two adjacent circles should be a prime.

Note: the number of first circle should always be 1.

HD_1016Prime Ring Problem(dfs)_第1张图片
 

Input
n (0 < n < 20).
 

Output
The output format is shown as sample below. Each row represents a series of circle numbers in the ring beginning from 1 clockwisely and anticlockwisely. The order of numbers must satisfy the above requirements. Print solutions in lexicographical order.

You are to write a program that completes above process.

Print a blank line after each case.
 

Sample Input
   
   
   
   
6 8
 

Sample Output
   
   
   
   
Case 1: 1 4 3 2 5 6 1 6 5 2 3 4 Case 2: 1 2 3 8 5 6 7 4 1 2 5 8 3 4 7 6 1 4 7 6 5 8 3 2 1 6 7 4 3 8 5 2
 

   

    此题用的方法巧妙,深搜加剪枝,如果输入N是奇数的话,由于起点从1开始,那么1-N之间一共有N / 2个偶数,N / 2 + 1个奇数,也就是奇数的个数比偶数多一个,那么把这N个数排成一个环,根据鸽巢原理,必然有两个奇数是相邻的,而两个奇数之和是偶数,偶数不是素数,所以我们得出结论,如果输入N是奇数的话,没有满足条件的排列。这样当N是奇数的时候,直接返回可。如果1-N之间每个数输入的几率相同,这个判断可以减少一半的计算量。再扩展一下,可以发现,任何一个满足条件的排列都有一个共同点:相邻的两个数奇偶性必然不同,原因是:两个奇数之和或者两个偶数之和都是偶数,而偶数一定不是素数,所以在选取当前元素的时候,比较一下它和前一个元素的奇偶性。再做决定,可以减少一部分计算量。由 于奇数 + 偶数 = 奇数, 而奇数的二进制表示中,最低位是1, 所以有下面的代码, 其中curValue是当前值, a[lastIndex]是前一个值.


#include<stdio.h>
#include<stdlib.h>

int prime[38]{  //巧妙的应用 
	0,0,1,1,0,1,0,1,0,
	0,0,1,0,1,0,0,0,1,
	0,1,0,0,0,1,0,0,0,
	1,0,1,0,1,0,0,0,0,
	0,1
};

bool isok(int a[], int lastIndex, int curValue){
	//if( lastIndex < 0 )//完全没必要判断,因为不可能小于零 
	//	return true;
	if(!prime[a[lastIndex]+curValue])  //判断相邻两个数的和是否为素数 
		return false;
	if(!((a[lastIndex]+curValue)&1))  //判断相邻两个数的奇偶性 
		return false;
	for(int i=0; i<=lastIndex; ++i){  //判重 
		if(a[i]==curValue)
			return false;
	}
return true;
}

void output(int a[], int n){
	for(int i=0; i<=n-1; ++i){
		if(i==n-1)
			printf("%d",a[i]);
		else 
			printf("%d ",a[i]);
	}
	printf("\n");
}

void cyclePrime(int a[], int n, int k){
	if(n&1)
		return;
	if(k==n){
		if(prime[a[0]+a[n-1]])  //并且首尾也满足相加为素数,输出 
			output(a,n);
	}
	else{
		for(int i=2;i<=n;++i){
			a[k]=i;
			if(isok(a,k-1,i))
				cyclePrime(a,n,k+1);
		}
	}
}

int main(){
	int n,m=0;
	while(scanf("%d",&n)==1){
		int a[25];
		a[0]=1;
		printf("Case %d:\n",++m);
		cyclePrime(a,n,1);
		printf("\n");
	}
return 0;
}



你可能感兴趣的:(HD_1016Prime Ring Problem(dfs))