原创文章转载请注明出处
摘要:枚举,棋盘翻转,位运算 , 三星
一. 题目翻译
1. 描述:
检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。
上面的布局可以用序列2 4 6 1 3 5来描述,第i个数字表示在第i行的相应位置有一个棋子,如下:
行号 1 2 3 4 5 6
列号 2 4 6 1 3 5
这只是跳棋放置的一个解。请编一个程序找出所有跳棋放置的解。并把它们以上面的序列方法输出。解按字典顺序排列。请输出前3个解。最后一行是解的总个数。
2. 格式:
INPUT FORMAT:
(checker.in)
一个数字N (6 <= N <= 13) 表示棋盘是N x N大小的。
OUTPUT FORMAT:
(checker.out)
前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。
SAMPLE INPUT:
6
SAMPLE OUTPUT:
2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4
1. 题意理解(将问题分析清楚,大致用什么思路):
这道题目最基本的思路就是枚举,枚举所有可能出现的组合。
这里有三个限制的条件,也就是题目中的列限制、正对角线限制、反对角线限制。我们使用三个数组来表示,数组中元素为1表示当前的这个节点不可用。
但是即使是这样枚举,题目也很有可能超时。可以按照题目当中的hint做一个简单的优化:如果棋盘的大小N是偶数,则第一行只需要枚举前N/2列,这样没搜索出一种情况以后,沿中线翻转就可以产生另一个解(由于只枚举前N/2列所以不会重复)
要特别注意的是,这种算法在计算题目解的个数时可以减少复杂度。但是在N=6时,枚举第一行的前3列仅能产生2个解,所以需要对N=6的情况要进行单独的枚举。
2. 具体实现(具体实现过程中出现的问题):
参考代码注释。
3. 需要注意的细节:
棋盘大小N等于6的情况要单独考虑。
4. 启示:
翻转棋盘求解非常有意思,大家还可以思考更好的优化方法。
这道题目还有大神使用位运算,大家可以了解一下位运算。
三. 代码
/*
ID:fightin1
LANG:JAVA
TASK:checker
*/
//package session_1_5_4;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.Scanner;
public class checker {
static int length;
static int[] result;
static int size;
static int[] columnInUse;
static int[] diagonalInUse1;
static int[] diagonalInUse2;
static PrintWriter pw;
public static void main(String[] args) {
try {
// Scanner in = new Scanner(System.in);
// pw = new PrintWriter(System.out);
Scanner in = new Scanner(new BufferedReader(new FileReader(
"checker.in")));
pw = new PrintWriter(new BufferedWriter(new FileWriter(
"checker.out")));
length = in.nextInt();
size = 0;
result = new int[length + 1];
columnInUse = new int[length + 1];
diagonalInUse1 = new int[2 * length + 1]; // "\" in use
diagonalInUse2 = new int[2 * length + 1]; // "/" in use
if (length == 6){
placeInRow(0);
} else {
if (length%2 == 0){
placeInRow(1);
size = 2*size;
} else {
placeInRow(1);
size = 2*size;
columnInUse[length/2+1] = 1;
diagonalInUse1[length/2 + length] = 1;
diagonalInUse2[length/2 + 2] = 1;
placeInRow(2);
}
}
pw.println(size);
pw.close();
in.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void placeInRow(int row){
if (row == length+1){
size ++ ;
if (size<=3){
pw.print(result[1]);
for (int i=2;i<=length;i++){
pw.print(" "+result[i]);
}
pw.println();
}
} else {
int bound = length;
if (row == 0){
row = 1;
} else if (row == 1){
bound = length/2;
}
for (int col = 1; col <= bound; col++){
int diagonal1 = col - row + length;
int diagonal2 = col + row ;
if(columnInUse[col]==0&&diagonalInUse1[diagonal1]==0&&diagonalInUse2[diagonal2]==0){
columnInUse[col] = 1;
diagonalInUse1[diagonal1] = 1;
diagonalInUse2[diagonal2] = 1;
result[row] = col;
placeInRow(row+1);
columnInUse[col] = 0;
diagonalInUse1[diagonal1] = 0;
diagonalInUse2[diagonal2] = 0;
result[row] = col;
}
}
}
}
}