ABC264のC問題 Matrix Reducingを解説します。
問題のポイント
A行列からどの行を選んで行列を作成するか?という部分でbit全探索という考え方を使いました。(列の選び方についても同様です。)
A行列が5×5行列、B行列が3×3行列であったとき、A行列の5行から3行を選ぶ必要があります。
選んだ行(列)を全てを列挙するのにbit全探索を利用します。
bit全探索では2進数をうまく利用してその桁に意味を持たせていきます。
上の5行の行列から3行を選ぶという例では5桁の2進数を考えます。
例えば、11001。
右から0桁目は1、1桁目は0、2桁目は0、3桁目は1、4桁目は1と見ることができ、今回の問題では下のような意味をもたせます。
i桁目が1であればi行目を選ぶ
すると、11001は、0行目、3行目、4行目を選んでできる行列という意味になります。
以下、5桁でできる2進数とその意味をざっと列挙してみます。
00000 => どの行も選ばない
00001 => 0行目を選ぶ
00010 => 1行目を選ぶ
.
.
00111 => 2行目と1行目と0行目を選ぶ
01000 => 3行目を選ぶ
01001 => 3行目と0行目を選ぶ
01010 => 3行目と1行目を選ぶ
01011 => 3行目と1行目と0行目を選ぶ
01100 => 3行目と2行目を選ぶ
.
.
11111 => 全ての行を選ぶ
こんな感じです。3行を選ぶ以外の全てのパターンが考えられている点に注意です。
今回の問題では3行だけを選ぶものを利用すればいいです。
(vectorのsizeでうまいことやっています。)
ざっと、bit全探索の考え方について解説しました。
入力例
4 5
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
2 3
6 8 9
16 18 19
回答例
#include
using namespace std;
using P = pair;
#define rep(i, n) for (int i = 0; i < (n); ++i)
int main() {
// ここから
int h1, w1, h2, w2;
cin >> h1 >> w1;
vector< vector < int > > a(h1, vector< int >(w1));
rep(i, h1) {
rep(j, w1) {
cin >> a[i][j];
}
}
cin >> h2 >> w2;
vector> b(h2, vector< int >(w2));
rep(i, h2) {
rep(j, w2) {
cin >> b[i][j];
}
}
// ここまで入力受け取り
// 行列Aからh2行選び、さらにw2列選んだ行列をcとして、行列bと等しいかをチェック
// bit全探索を用いてどの行、どの列を選ぶかを考えている
for (int bit_h = 0; bit_h < (1 << h1); bit_h++) {
for (int bit_w = 0; bit_w < (1 << w1); bit_w++) {
vector< int > tmp_h; // どの行を選ぶかを管理するvectorを準備 [0,1,2]みたいな感じにしていく
for (int i = 0; i < h1; i++) {
if ((bit_h >> i) & 1) tmp_h.emplace_back(i);
}
vector< int > tmp_w; // どの列を選ぶかを管理するvectorを準備
for (int j = 0; j < w1; j++) {
if ((bit_w >> j) & 1) tmp_w.emplace_back(j);
}
if (tmp_h.size() != h2) continue; // 長さがh2と合わないものもあるので、その場合はcontinue
if (tmp_w.size() != w2) continue; // 列も同様
vector> c(h2, vector< int >(w2));
rep(i, h2) {
rep(j, w2) {
c[i][j] = a[tmp_h[i]][tmp_w[j]]; // tmp_hは[0,1,3]のようになっている。0行目、1行目、3行目を選択するという意味
// tmp_wも同様
}
}
if (c == b) { // vectorが等しいかどうかは"=="で判定可能
cout << "Yes" << endl;
return 0;
}
}
}
cout << "No" << endl;
return 0;
}
コメント