1432.チェス盤チャレンジ
与えられたN×NN×NN××Nのチェス盤、NNを置いてくださいNチェスの駒、要件は次のとおりです。
- 各行と列にちょうど1つのポーンがあります
- 各対角線上に最大で1つのピースが存在できます
1 2 3 4 5 6
-------------------------
1 | | O | | | | |
-------------------------
2 | | | | O | | |
-------------------------
3 | | | | | | O |
-------------------------
4 | O | | | | | |
-------------------------
5 | | | O | | | |
-------------------------
6 | | | | | O | |
-------------------------
上の図は、N = 6の場合N = 6であることを示しています。N=.6プログラムシーケンスの解を使用2 4 6 1 3 5
して、行の最初の列の位置から6番目の行まで順番に指定されたシーケンスを記述できる場合。ここで、表示の各行が断片化します。
N×NN×Nを指定してプログラムを作成してくださいN××Nのチェス盤とNNN個、上記の条件を満たすものをすべて見つけてください。
入力フォーマット
1行、整数NNN。
出力形式は
合計4行で、それぞれ3行が整数のシーケンスを出力し、1つの可能な配置スキームであるiiのシーケンスを記述します。iの数はiiを意味します行iのチェスの駒を配置する列の位置。
これらの3行で記述されるスキームは、辞書式順序で1番目、2番目、および3番目にランク付けされた整数シーケンスを持つスキームである必要があります。
4行目は、可能な配置オプションの総数を表す整数を出力します。
データ範囲
6≤N≤136≤N≤136≤N≤1 3
入力サンプル:
6
サンプル出力:
2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4
アイデア
この質問はn
女王の質問に似ています。dfs
各スキームをシミュレートし、最終的に法的なスキームを出力する必要があります。図の青と緑の線はすべて対角線を表していることに注意してください。n*n
チェス盤の場合、対角線と反対側の対角線がすべて2n - 1
線であることを見つけるのは難しくありません。
- 行ごとに詳細に検索し、各行のすべての列を列挙して、列と対角線の間に競合があるかどうかを判断します
- バックトラックするときは、シーンを復元するように注意してください
- 使用可能なスキームのシーケンスを出力する必要があり、現在選択されている列番号を格納するために配列が必要です
- 主対角線と補助対角線は、開発ステータスを識別するためにアレイによって識別でき、行と列の番号とその対角線の間の対応する関係を決定する必要があります。
- 行番号と列番号を組み合わせて対角行に番号を付けます。繰り返されない限り、対応する関係は一意ではありません。
- たとえば、xxの場合x行yy主対角にx + y x + yの番号が付けられたy列バツ+y、補助対角数はx − y + nx−y + nですx - y+n(nnnはボードの長さに加えて、最終的な数値が負の数にならないようにするためのこのオフセットです。これは、配列のインデックス作成に便利です)
Javaコード
import java.util.Scanner;
public class Main {
private static final int N = 15;//最多13行,我们开大点,假设15行
private static int n;//当前是第几行,注意这里为了方便,我们从1开始计数
private static boolean[] col = new boolean[N];//标记当前列是否放了棋子
private static boolean[] dg = new boolean[N * 2];//对角线是否放了棋子
private static boolean[] udg = new boolean[N * 2];//副对角线是否放了棋子
private static int[] path = new int[N];//一种方案
private static int cnt;//总方案数
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
dfs(1);//为了方便,我们让下标从1开始,即让索引和行号一样
System.out.println(cnt);
}
private static void dfs(int x) {
//传入的x代表的就是行索引
if(x > n){
//放满棋盘了
cnt++;
if(cnt <= 3){
//输出前三个答案
for(int i = 1;i <= n;i++){
System.out.print(path[i] + " ");
}
System.out.println();
}
return;
}
for(int y = 1;y <= n;y++){
//当前行对应的每一列尝试放棋子
if(!col[y] && !dg[x + y] && !udg[x - y + n]){
//该点对应的列、左斜对角线、右斜对角线都没有棋子,则可以放。
path[x] = y;//第x行的第y列放一个棋子
col[y] = dg[x + y] = udg[x - y + n] = true;
dfs(x + 1);//进行下一行
//恢复现场
col[y] = dg[x + y] = udg[x - y + n] = false;
path[x] = 0;
}
}
}
}