対応するletecodeリンク:
トピックの説明:
問題解決のアイデア:
ルールを見つけましょう、最初に4人の女王の問題を見てみましょう
たとえば、次の4 * 4グリッドで、グリッドの1つにクイーンを入力すると、この行、この列、および左側と右側の対角線にクイーンを含めることはできません。
まず、最初の行と最初の列にクイーンを配置します。次に、対応する行も対角線もクイーンを配置できません。
2行目まで。2行目では、競合があるため、1列目と2列目にクイーンを入力できません。ただし、列3にクイーンを入力できます。
3行目では、入力に競合があることがわかります。これは、前に選択したものが間違っていたことを示しています。前の手順に戻ると、2番目の手順では、3番目の列だけでなく、4番目の列も選択できることがわかりました。3番目の列は適切ではないため、4番目の列を選択します。
後者についても同じことが言えますが、再帰が戻ったときに、前の黄変のために回転できなかった位置を再回転させることができます。
現在の難しさは、列と対角線にラベルを付ける方法です。列と簡単にunordered_setタグを使用できます。行では、この行にクイーンを配置した直後に次のレイヤーに戻ることができますが、対角線はどうでしょうか。少し複雑に感じますが、複雑ではありません。女王の位置がi、jの場合、その対角線の位置はi + 1、j + 1、i + 1、j-1であり、対角線があることがわかります。方向線の座標は固定値としてijに減算され、他の対角座標の加算は固定値としてi + jであるため、ハッシュテーブルレコードを使用するだけで済みます。
詳しくはこちらをご覧ください
class Solution { public: vector<vector<bool>>visit;//标记某个位置是否放过皇后 unordered_set<int>col;//标记这一列不能放皇后 unordered_set<int>pia;//标记对角线不能放皇后 unordered_set<int>na; int _n;//数量 vector<vector<string>>ans;//记录答案 vector<vector<string>> solveNQueens(int n) { visit.resize(n,vector<bool>(n));//初始化为false; this->_n=n; dfs(0);//递归 return ans; } void dfs(int i) { if(i==_n)//如果已经走到最后一行说明 { ceraterAns();//产生答案了 return; } for(int j=0;j<_n;j++) { if(col.count(j)||pia.count(i+j)||na.count(i-j))//说明被标记过不能够放皇后直接 //continue即可跳过了 { continue; } visit[i][j]=true;//标记这个这个位置已经放过皇后 col.insert(j);//标记这一列不能放皇后 pia.insert(i+j);//对角线标记 na.insert(i-j); dfs(i+1);//这一层放过了直接到下一层即可 visit[i][j]=false;//递归返回之后需要将之间的标记去除 col.erase(j); pia.erase(i+j); na.erase(i-j); } } void ceraterAns() { vector<string>tmp; for(int i=0;i<_n;i++) { string str; for(int j=0;j<_n;j++) { if(visit[i][j]) { str.push_back('Q'); } else { str.push_back('.'); } } tmp.push_back(str); } ans.push_back(tmp); } };
トピックの説明:
問題解決のアイデア:
この質問は基本的に前の質問と同じですが、前の質問のより単純なバージョンです。このアイデアは上記の質問ですでに言及されています。上記の質問のコードをコピーするだけです。
対応するコード:
class Solution { public: vector<vector<bool>>visit;//标记某个位置是否放过皇后 unordered_set<int>col;//标记这一列不能放皇后 unordered_set<int>pia;//标记对角线不能放皇后 unordered_set<int>na; int _n;//数量 int ans=0; int totalNQueens(int n) { visit.resize(n,vector<bool>(n));//初始化为false; this->_n=n; dfs(0);//递归 return ans; } void dfs(int i) { if(i==_n)//如果已经走到最后一行说明 { ans++;//产生答案了 return; } for(int j=0;j<_n;j++) { if(col.count(j)||pia.count(i+j)||na.count(i-j))//说明被标记过不能够放皇后直接 //continue即可跳过了 { continue; } visit[i][j]=true;//标记这个这个位置已经放过皇后 col.insert(j);//标记这一列不能放皇后 pia.insert(i+j);//对角线标记 na.insert(i-j); dfs(i+1);//这一层放过了直接到下一层即可 visit[i][j]=false;//递归返回之后需要将之间的标记去除 col.erase(j); pia.erase(i+j); na.erase(i-j); } } };
以下は、letecodeの繰り返しの質問です。
トピックの説明:
対応するコード:
class Solution { public: vector<vector<bool>>visit;//标记某个位置是否放过皇后 unordered_set<int>col;//标记这一列不能放皇后 unordered_set<int>pia;//标记对角线不能放皇后 unordered_set<int>na; int _n;//数量 vector<vector<string>>ans;//记录答案 vector<vector<string>> solveNQueens(int n) { visit.resize(n,vector<bool>(n));//初始化为false; this->_n=n; dfs(0);//递归 return ans; } void dfs(int i) { if(i==_n)//如果已经走到最后一行说明 { ceraterAns();//产生答案了 return; } for(int j=0;j<_n;j++) { if(col.count(j)||pia.count(i+j)||na.count(i-j))//说明被标记过不能够放皇后直接 //continue即可跳过了 { continue; } visit[i][j]=true;//标记这个这个位置已经放过皇后 col.insert(j);//标记这一列不能放皇后 pia.insert(i+j);//对角线标记 na.insert(i-j); dfs(i+1);//这一层放过了直接到下一层即可 visit[i][j]=false;//递归返回之后需要将之间的标记去除 col.erase(j); pia.erase(i+j); na.erase(i-j); } } void ceraterAns() { vector<string>tmp; for(int i=0;i<_n;i++) { string str; for(int j=0;j<_n;j++) { if(visit[i][j]) { str.push_back('Q'); } else { str.push_back('.'); } } tmp.push_back(str); } ans.push_back(tmp); } };