HDU 1016(Java) 好大一个坑!!!

Prime Ring Problem

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

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.

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

深搜的一道水题,原先用C++AC了,因为要学习Java,就用Java撸了一遍。然而悲剧就这么发生了,同样的逻辑代码,符号题目要求的输出,提交了一整天总是presentation error,万般无奈之下去网上搜AC代码,然而没有Java版的,所以只好对着C语言一个个看,后来一步一步调试,才发现要在Case %d:后面再加个空格(可是题目描述和C++版中都没有这个空格)。~~~~,虽然Java运行慢,用Java打比赛的人少,但也不能这么坑人吧!


import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static int kase = 0,n;
    public static int[] circles = new int[50];
    public static boolean[] flag = new boolean[50],primes = new boolean[50];
    static boolean DEBUG = false;
    static void debug(){
        System.out.print("***");
    }
    public static void initPrimes(){
        Arrays.fill(primes, true);
        for(int i=2;i<=30;i++){
            for(int j=i+i;j<50;j+=i){
                if(j%i==0) primes[j] = false;
            }
        }
        primes[0]=primes[1] = false;
    }
    public static void DFS(int i){
        if(i==n){
            if(primes[1+circles[n-1]]){
                for(int j=0;j<n;j++){
                    if(j==n-1) System.out.print(circles[j]);
                    else System.out.print(circles[j]+" ");
                }
                System.out.println();
            }
            return ;
        }
        else{
            for(int j=2;j<=n;j++){
                if(flag[j]){
                    if(primes[j+circles[i-1]]&&((j+circles[i-1])&1)!=0){//相邻的数奇偶性不同,剪枝!
                        flag[j] = false;
                        circles[i] = j;
                        DFS(i+1);
                        flag[j] = true;
                    }
                }
            }
        }
        return ;
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in = new Scanner(System.in);
        initPrimes();
        while(in.hasNext()){
            n = in.nextInt();
            //就是这个坑!!
            System.out.printf("Case %d: \n", ++kase);
            if(n==1){
                System.out.println(1);
                System.out.println();
                continue;
            }
            else if((n&1)!=0){
                System.out.println();
                continue;
            }
            Arrays.fill(flag, true);
            circles[0] = 1;
            flag[1] = false;
            DFS(1);
            System.out.println();
        //  if(DEBUG) debug();
        }
    }

}

note:
1.数据规模小,所以把1~37的所有素数都找到了,打表空间换时间。
2.数据优化:再考虑输入的特点,如果输入N是奇数的话,由于起点从1开始,那么1-N之间一共有N / 2个偶数,N / 2 + 1个奇数,也就是奇数的个数比偶数多一个,那么把这N个数排成一个环,根据鸽巢原理,必然有两个奇数是相邻的,而两个奇数之和是偶数,偶数不是素数,所以我们得出结论,如果输入N是奇数的话,没有满足条件的排列。这样当N是奇数的时候,直接返回即可。如果1-N之间每个数输入的几率相同,这个判断可以减少一半的计算量。
3.剪枝:两个奇数之和或者两个偶数之和都是偶数,而偶数一定不是素数,所以在选取当前元素的时候,比较一下它和前一个元素的奇偶性。再做决定,可以减少一部分计算量。
4.位运算按位于判断整数N奇偶性:由于奇数的二进制表示中,最低位是1,N与1按位与运算(N&1)后结果是1,则说明N是一个奇数,否则是一个偶数。即输出结果环中相邻的数奇偶性一定不相同

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值