問題の説明
制約(i行とj列のN * N、1または0のテーブル、j-1 thisとして表される)を指定して、0〜N-1(つまり、各数値は1回しか出現できない)の配置を見つけます。番号i-1の後に数字を表示することはできません。また、i番目の行とi番目の列が0であることを確認してください。この配列を自然数として扱い、K番目の配列を昇順で見つけます。
データサイズと合意
N <= 10、K <= 500000
入力フォーマット
最初の行はNとK、次のN行、各行のN番号、0はいいえ、1ははいを意味します
出力フォーマット
リクエストされた手配
入力例
3 2
0 1 1
1 0 0
0 1 0
出力例
1 0 2
説明:
N = 3の場合、制限なし
最初:0 1 2 2
番目:0 2 1
3番目:1 0 2
4番目:1 2 0
5番目:2 0 1
6番目:2 1 0
制約を与えられたタイトルがバック1 2ため表示されないことができ、0〜2が後ろに現れることができない
021:第
二:102
三:210
HTTPSから参照://blog.csdn。 net / weixin_44778155 /記事/詳細/ 104672498この
質問は理解するのが難しいので、簡単に説明しましょう。
まず、0〜n-1の完全な配置を生成します。たとえば、n = 3の場合、完全な配置は次のようになります。
最初:0 1 2 2
番目:0 2 1
3番目:1 0 2
4番目:1 2 0
5番目:2 0 1
6番目:2 1 0
次に制限を与えると、この制限はn * nの行列を指定して、この行列を記録するために2次元配列vis [] []を開きます。
この行列では、左上から右下への対角線i = jの0は役に立たないので、見る必要はありません。
他の位置に0があるかどうかのみを確認します。例では、vis [1] [2] = 0、vis [2] [0] = 0です。
ない2 密着してバックでいくつかの数字1と2の間では、一方の背後にあるとすることが可能です。したがって、上記の6つの順列の最初と4番目は要件を満たしていないため、削除されます。
その場合、0は2に厳密に従うことができません。上記の5番目が削除されます。
したがって、残りの順列は次のとおりです。
最初:0 2 1
2番目:1 0 2
3番目:2 1 0
次にk = 2をサンプリングするので、2番目の完全な配列1 0 2 を出力する
と、このコードは理解しやすくなります。
1 #include <bits/stdc++.h> 2 using namespace std; 3 int n, k, cnt; 4 int a[20]; 5 int vis[20][20]; 6 bool check() { //check函数用于判断当前这个全排列是否符合题意 7 for (int i = 1; i < n; i++) { //遍历这个全排列,看看是否存在某个数不能紧贴在某个数后面的情况 8 if (vis[a[i - 1]][a[i]] == 0) { 9 return false; 10 } 11 } 12 return true; 13 } 14 int main() { 15 cin >> n >> k; 16 for (int i = 0; i < n; i++) { 17 a[i] = i; //生成0~n-1的序列 18 } 19 for (int i = 0; i < n; i++) { //输入限制 20 for (int j = 0; j < n; j++) { 21 cin >> vis[i][j]; 22 } 23 } 24 do { 25 if (check()) { //判断这个序列是否符合要求 26 if (++cnt == k) { //若符合要求,++cnt。求到第k个符合条件的全排列的话,break 27 break; 28 } 29 } 30 } while (next_permutation(a, a + n)); 31 for (int i = 0; i < n; i++) { //输出这个全排列 32 cout << a[i] << " "; 33 } 34 cout << endl; 35 return 0; 36 }