8人の女王の問題は、女王をチェス盤に置き、お互いを攻撃して解決策を模索しないことです。駒を交換すると、8台の車、8頭の馬、8頭の兵士、8頭の王の問題も発生します。この問題では、チェスの駒が車に交換され、チェス盤を交換する必要がありましたが、正確にはいくつかの変更が加えられました。たとえば、現在n * nのチェス盤があります。いくつかのグリッドでいくつかの穴を選びます。当然、これらの穴はチェスの駒には使用できず、見落とされます。さらに、車はその仲間と攻撃した可能性があります。さて、考えてみれば、攻撃中に穴を踏むと自分を破壊してしまいます。したがって、車の攻撃範囲は穴で終わります。
この質問では、チェス盤のスケールnと掘削状況を示します。k台の車を配置するための計画の数を見つけます(kから0から配置可能な最大の車の数)。
データのスケールと規則
n <= 8入力
最初の行の整数nは、チェス盤のサイズを示します。
次のn行。各行には、スペースで区切られた0または1のn個の数字があります。0の形状は穴を示し、1は穴がないことを示します。アウトプット
複数の行、i番目の行はi台の車を配置する計画の数を表します
入力例
3 1 0 1 1 1 1 1 0 1
出力例
7 12 4
タイトルが示すように、この質問は「nクイーンの質問」という遡及的方法の古典的な質問に基づいてい ます。この質問を深く理解する前に、「 nクイーンの質問」「Nクイーン」の理解を深めるために前の記事を読むことを強くお勧めします。 そして、2Nクイーン問題分析」
I. nクイーンの問題の簡単な紹介
上記の記事でstep変数をご覧になりましたか?これは、ステップクイーンの配置を参照しています。また、ステップラインでのクイーンの配置も参照しています。
nクイーンの問題はnクイーンにしか入れることができず、各行に1つ、各列に1つしかありません。
ステップを決定したら、この行の各列を反復処理して、条件を満たす位置を見つけます。
次に、この質問はnクイーンの問題とどのように異なりますか
質問:さて、攻撃中に穴を踏むと、自分を破壊します。したがって、車の攻撃範囲は穴で終わります。
例:ラインは1 0 1
この行の最初の列が車を落とした場合、車の攻撃範囲は2列目の穴で終了するため、3番目の列は攻撃されません。
だから:
Q:ポイント(i、j)が訪問されたことがわかったら、次の場所を見つけるためにどこに行かなければなりませんか?
回答:はい、適格な位置を見つけるには、(i、j)の後のすべてのポイントをトラバースする必要があります。同じ列を使用することもできます。
Q:資格のあるポジションとは何ですか?
回答:
同じ行の位置が(x、y)であると想定します:(x、1〜y)に1があり、それらの間に0がない場合、攻撃されます。安全な位置が
同じ列にある場合でも、1 in(1〜x、y)があり、それらの間に0のブロックがない場合は、正当な位置ではなく攻撃され、そうでなければ安全な位置も
ここでは、特定のポイント(x、y)が安全かどうかを判断するチェック()を記述します。
bool check(int x,int y,int n) {
for(int i=x-1; i>=1; i--) {
if(map[i][y]==0) break; //如果在遇到1之前遇到0,那么它是安全的
if(vis[i][y]==1) return false; //如果还没遇到0就遇到了1,那就它是危险的
}
for(int i=y-1; i>=1; i--) {
if(map[x][i]==0) break;
if(vis[x][i]==1) return false;
}
return true;
}
3、達成する方法
nクイーン問題と同様に、プロセスは変数を説明するDFSアルゴリズムを使用して実装されます。
dfs(int x,int y,int t,int n) // 访问了(x,y);此时t个车;n为棋盘规模
int num[maxn] // num[i]表示i个车的方案数
DFSアルゴリズムプロセスでは、特定の分析がコードに記述されています。
void dfs(int x,int y,int t,int n) {
if(t<=n*n) num[t]++;
for(int i=x; i<=n; i++) { //遍历 (x,y)及其之后的所有点,从(1,1)开始
int j; // 遍历:x行y列之后的+下面所有行
if(i==x) j=y;
else j=1;
for(;j<=n; j++) {
if(vis[i][j]==0 && map[i][j]==1 && check(i,j,n)) { //满足条件的访问:没访问过 && 是陆地 && 不被攻击
vis[i][j]=1;
dfs(i,j,t+1,n);
vis[i][j]=0; // 回溯到DFS前的状态
}
}
}
}
完全なコードは次のとおりです。
#include<cstdio>
#include<iostream>
using namespace std;
const int maxn = 10;
int map[maxn][maxn];
int vis[maxn][maxn];
int num[maxn];
bool check(int x,int y,int n) {
for(int i=x-1; i>=1; i--) {
if(map[i][y]==0) break; //如果在遇到1之前遇到0,那么它是安全的
if(vis[i][y]==1) return false; //如果还没遇到0就遇到了1,那就它是危险的
}
for(int i=y-1; i>=1; i--) {
if(map[x][i]==0) break;
if(vis[x][i]==1) return false;
}
return true;
}
void dfs(int x,int y,int t,int n) {
if(t<=n*n) num[t]++;
for(int i=x; i<=n; i++) {
int j;
if(i==x) j=y;
else j=1;
for(;j<=n; j++) {
if(vis[i][j]==0 && map[i][j]==1 && check(i,j,n)) {
vis[i][j]=1;
dfs(i,j,t+1,n);
vis[i][j]=0;
}
}
}
}
int main() {
int n;
cin>>n;
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
cin>>map[i][j];
}
}
dfs(1,1,0,n);
for(int i=1; i<=n*n;i++) {
if(num[i]!=0) cout<<num[i]<<endl;
}
return 0;
}
それがあなたを助けるなら、それは大きな名誉です!