标签:
转载声明:原文转自http://www.cnblogs.com/xiezie/p/5576273.html
题意:
一个环是用图中所示的n个圆组成的。把自然数1、2、……、n分别放入每个圆中,并在相邻的圆中的数值总和为一个质数。
注:第一圈数应该是1。
输出:
输出格式显示为下面的示例。每一行代表在环里圆中的数从1开始顺时针和逆时针。数字的数量必须满足上述要求。按字典顺序打印解决方案。
你是写一个程序,完成上述过程。
每一种情况下打印一条空白线。
题目分析:
首先,因为需要遍历多次,质数不可能每次判断的时候都重新计算,应该生产质数表(0<n<20,因此质数表中的质数小于40)。
java算法如下:
/* * 输入数字,作为序号传入 * 判断是否质数 * */ static boolean isAPrimeInForty(int num){ if(isPrimes[num]==1){ return true; } return false; } /* * 生产序号为0-39的0,1序列 * 1代表为质数 * 0代表为非质数 * */ static int[] isPrimes = createPrimes(); static int[] createPrimes(){ int[] primes = new int[40]; for(int i = 2 ; i != 40 ; i ++ ){ if(isAPrime(i)){ primes[i] = 1; } } return primes; } //判断是否质数 static boolean isAPrime(int num){ int len = (int) (Math.sqrt(num)+1); for(int i = 2 ; i != len ; i ++){ if(num%i==0){ return false; } } return true; }
解题:
第一次,由于最近搞了全排列,我的解题思路是:将所有数进行字典序全排列(由于数字是顺序输入数组,我在字典序排列中省去了排序的过程),并判断是否符合题中条件。如果是则存储(因此,顺时针逆时针都包括)或者直接输出。
结果:Time Limit Exceeded----------不过我相信这样做答案一定是正确的
代码如下:
import java.util.*; import java.io.*; public class Main{ public static void main(String[] arg){ Scanner scan = new Scanner(new BufferedInputStream(System.in)); int n; int count = 1; while(scan.hasNextInt()){ n = scan.nextInt(); System.out.println("Case "+ count+++ ":" ); int[] nums = new int[n]; for(int i = 0 ; i != n; i ++){ nums[i] = i+1; } getAllPermutationsAndCheck(nums,1,n-1); System.out.println(); } scan.close(); } static boolean isAnswer(int[] nums){//判断数组是否符合条件 int len = nums.length; for(int i = 0 ; i != len ; i ++ ){ int sum = nums[i%len] + nums[(i+1)%len]; if(!isAPrimeInForty(sum)){ return false; } } return true; } static boolean isAPrime(int num){//判断是否质数 int len = (int) (Math.sqrt(num)+1); for(int i = 2 ; i != len ; i ++){ if(num%i==0){ return false; } } return true; } static void getAllPermutationsAndCheck(int[] cs,int start,int len){//cs为字典序数组 if(cs==null) return; while(true) { if(isAnswer(cs)){ for(int j = 0 ; j != cs.length; j ++){ if( j == cs.length -1){ System.out.print(cs[j]); break; } System.out.print(cs[j] + " "); } System.out.println(); } int j=start+len-2,k=start+len-1; while(j>=start && cs[j]>cs[j+1]) --j; if(j<start) break; while(cs[k]<cs[j]) --k; swap(cs,k,j); int a,b; for(a=j+1,b=start+len-1;a<b;++a,--b) { swap(cs,a,b); } } } static boolean isAPrimeInForty(int num){//判断是否质数 for(int i = 0 ; i != 12 ; i ++ ){ if(num>primes[i]){ continue; } if(num==primes[i]){ return true; } if(num<primes[i]){ return false; } } return false; } static int[] primes = createPrimes(); static int[] createPrimes(){ int[] primes = new int[12]; int count = 0; for(int i = 2 ; i != 40 ; i ++ ){ if(isAPrime(i)){ primes[count] = i; count++; } } return primes; } static void swap(int[] nums , int i , int j){ int t; t = nums[i]; nums[i] = nums[j]; nums[j] = t; } }
当然,当我全排列10个数的时候,秒输出,当我全排列12个数的时候,半天都输出不了~
只能说明:全排列是最差的暴力破解,没有进行剪枝
下面一个思路是:深度搜索
同样是字典序全排列(不过是从1-n的全排列,有了具体场景)
但是在字典序全排列过程中,进行剪枝,遇到一个前后相加不为质数的就跳过(省去了后面的全排列)
结果:Accepted 执行占用时间:2698MS 执行占用内存:13940K
具体java算法如下:
import java.util.*; import java.io.*; public class Main{ public static void main(String[] arg){ Scanner scan = new Scanner(new BufferedInputStream(System.in)); int n; int count = 1; answer[0] = 1; while(scan.hasNextInt()){ n = scan.nextInt(); System.out.println("Case "+ count+++ ":" ); checkAndOutput(n,1); System.out.println(); } scan.close(); } static int[] answer = new int[21]; static int[] isUsed = new int[21]; static void checkAndOutput(int n,int index) {//index为数组的序号 int len = n+1; int last = n-1; if(index == n){ for(int i=0; i != n ; i ++ ){ if(i == last){ System.out.println(answer[i]); return; } System.out.print(answer[i]+" "); } } for(int i = 2 ; i != len ; i ++ ){//数组序号为index的遍历 if(isUsed[i] == 0){ if(!isAPrimeInForty(i + answer[index-1])){ continue; } isUsed[i]=1; answer[index] = i; if(index==last){ if(!isAPrimeInForty(1+ answer[index])){//增加一步头尾相加判断 isUsed[i]=0; continue; } } checkAndOutput(n,index+1); isUsed[i]=0; } } } /* * 输入数字,作为序号传入 * 判断是否质数 * */ static boolean isAPrimeInForty(int num){ if(isPrimes[num]==1){ return true; } return false; } /* * 生产序号为0-39的0,1序列 * 1代表为质数 * 0代表为非质数 * */ static int[] isPrimes = createPrimes(); static int[] createPrimes(){ int[] primes = new int[40]; for(int i = 2 ; i != 40 ; i ++ ){ if(isAPrime(i)){ primes[i] = 1; } } return primes; } //判断是否质数 static boolean isAPrime(int num){ int len = (int) (Math.sqrt(num)+1); for(int i = 2 ; i != len ; i ++){ if(num%i==0){ return false; } } return true; } static void swap(int[] nums , int i , int j){ int t; t = nums[i]; nums[i] = nums[j]; nums[j] = t; } }
标签:
原文地址:http://www.cnblogs.com/xiezie/p/5576273.html