题解:P11942 [KTSC 2025] 重塑矩阵 / grid_encoding
NB 题。
我们建立一张
那么我们回过头看题目里那个条件实际上在说,这两行两列构成了一个四元环。那么约束实际上就是,这张二分图里不存在四元环。现在考虑如果这张二分图存在六元环
二分图将所有点分为两色,一黑一白,在原题中就对应行节点和列节点。我们考查所有无入度的点,于是它们之间一定两两无边,于是它们全都同色,并且任意删掉一些点,剩余的无入度点也都会满足这一点。于是把这些点全部删掉后新的无入度点也一定都同色,且一定和第一批点异色,且在这两批点里任意各选一个都一定有第一批连向第二批的边。以此类推,最终这个图是被分成了若干层。任取两个异色点,层高的连向层低的。注意这里“层”的定义和批是反的。
于是现在只需要确定每个节点的层就可以了。我们只需要传过去一个森林,保证原图中每个点都有层恰好比它高 1 的点连向它(只要有),根恰好是最低层的所有点,就做完了。
#include <bits/stdc++.h>
using namespace std;
void select(int x, int y);
void send(vector<vector<int>> A) {
int n = A.size();
vector<int> cx(n), cy(n);
function<void(int)> dfsx, dfsy;
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j) ++(!A[i][j] ? cx[i] : cy[j]);
dfsx = [&](int i) {
cx[i] = -1;
for (int j = 0; j < n; ++j)
if (A[i][j] == 1) --cy[j];
for (int j = 0; j < n; ++j)
if (A[i][j] == 1 && !cy[j]) select(i, j), dfsy(j);
};
dfsy = [&](int j) {
cy[j] = -1;
for (int i = 0; i < n; ++i)
if (A[i][j] == 0) --cx[i];
for (int i = 0; i < n; ++i)
if (A[i][j] == 0 && !cx[i]) select(i, j), dfsx(i);
};
for (int i = 0; i < n; ++i)
if (!cx[i]) dfsx(i);
for (int j = 0; j < n; ++j)
if (!cy[j]) dfsy(j);
}
vector<vector<int>> reconstruct(vector<vector<int>> B) {
int n = B.size();
vector<int> dx(n), dy(n);
function<void(int)> dfsx, dfsy;
dfsx = [&](int i) {
for (int j = 0; j < n; ++j)
if (B[i][j] == 1 && !dy[j]) dy[j] = dx[i] + 1, dfsy(j);
};
dfsy = [&](int j) {
for (int i = 0; i < n; ++i)
if (B[i][j] == 0 && !dx[i]) dx[i] = dy[j] + 1, dfsx(i);
};
for (int i = 0; i < n; ++i) {
int j = 0;
while (j < n && B[i][j] != 0) ++j;
if (j == n) dfsx(i);
}
for (int j = 0; j < n; ++j) {
int i = 0;
while (i < n && B[i][j] != 1) ++i;
if (i == n) dfsy(j);
}
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j) B[i][j] = dx[i] < dy[j];
return B;
}