vector<vector<int>> buildGraph(vector<vector<int>> &matrix) { int M = matrix.size(), N = matrix.front().size(), P = M * N; vector<vector<int>> G(P); vector<int> aux;
aux.resize(N); for (int i = 0; i < M; ++i) { // 考虑每行 for (int j = 0; j < N; ++j) aux[j] = j; sort(aux.begin(), aux.end(), [&](int a, int b){ return matrix[i][a] < matrix[i][b]; });
for (int k = 1; k < N; ++k) { int p = i * N + aux[k-1], q = i * N + aux[k]; G[p].push_back(q); // 较大元素加入较小元素的邻接列表 } }
aux.resize(M); for (int j = 0; j < N; ++j) { // 考虑每列 for (int i = 0; i < M; ++i) aux[i] = i; sort(aux.begin(), aux.end(), [&](int a, int b){ return matrix[a][j] < matrix[b][j]; });
for (int k = 1; k < M; ++k) { int p = aux[k-1] * N + j, q = aux[k] * N + j; G[p].push_back(q); // 较大元素加入较小元素的邻接列表 } }
vector<int> bfs(vector<vector<int>> &G, vector<int> &in){ // in 数组记录每个节点的入度 int P = G.size(); // P = M * N, 节点总数量 deque<int> Q; vector<int> ans(P, 1); for (int i = 0; i < P; ++i) // 从所有入度为 0 的节点开始 if (in[i] == 0) Q.push_back(i);
while (!Q.empty()) { int p = Q.front(); Q.pop_front(); for (int q : G[p]) { ans[q] = max(ans[q], ans[p] + 1); if (--in[q] == 0) // 如果所有节点的入度都计算过, 则秩已经确定, 可以入队了 Q.push_back(q); } } return ans; }
上面是一个使用广搜的拓扑排序算法. 前面建图的时候需要顺便求出每个节点的入度, 存放在 in 数组中. 因为图中不会有环, 所以当队列 Q 为空时, 所有节点的秩都已计算完毕.
intfind(vector<int> &pi, int a){ if (pi[a] == a) return a; return pi[a] = find(pi, pi[a]); } voidmerge(vector<int> &pi, int a, int b){ a = find(pi, a), b = find(pi, b); if (a != b) pi[a] = b; }
vector<vector<int>> matrixRankTransform(vector<vector<int>>& matrix) { int M = matrix.size(), N = matrix.front().size(), P = M * N;
// 1. 并查集合并相同元素 vector<int> pi(P); // 并查集用到的 pi 数组 vector<vector<int>> rows(M, vector<int>(N)), cols(N, vector<int>(M)); // 记录排序后的各行各列 for (int i = 0; i < P; ++i) pi[i] = i; for (int i = 0; i < M; ++i) { auto &aux = rows[i]; for (int j = 0; j < N; ++j) aux[j] = j; sort(aux.begin(), aux.end(), [&](int a, int b){ // 对每行排序 return matrix[i][a] < matrix[i][b]; }); for (int k = 0; k < N;) { int j = aux[k], n = matrix[i][j]; while (k < N && n == matrix[i][aux[k]]) // 用并查集合并相同的元素 merge(pi, i*N + j, i*N + aux[k]), ++k; } } for (int j = 0; j < N; ++j) { auto &aux = cols[j]; for (int i = 0; i < M; ++i) aux[i] = i; sort(aux.begin(), aux.end(), [&](int a, int b){ // 对每列排序 return matrix[a][j] < matrix[b][j]; }); for (int k = 0; k < M;) { int i = aux[k], n = matrix[i][j]; while (k < M && n == matrix[aux[k]][j]) // 用并查集合并相同的元素 merge(pi, i*N + j, aux[k]*N + j), ++k; } }
// 2. 建图 vector<vector<int>> G(P); vector<int> in(P); // in 数组记录入度 for (int i = 0; i < M; ++i) { // 考虑每行 auto &aux = rows[i]; for (int k = 1; k < N; ++k) { int p = find(pi, i*N + aux[k-1]), q = find(pi, i*N + aux[k]); // 要找到并查集的根节点 if (p != q) G[p].push_back(q), // 较大元素加入较小元素的邻接列表 ++in[q]; // 较大元素的入度加一 } } for (int j = 0; j < N; ++j) { // 考虑每列 auto &aux = cols[j]; for (int k = 1; k < M; ++k) { int p = find(pi, aux[k-1]*N + j), q = find(pi, aux[k]*N + j); // 要找到并查集的根节点 if (p != q) G[p].push_back(q), // 较大元素加入较小元素的邻接列表 ++in[q]; // 较大元素的入度加一 } }
// 3. 广搜 deque<int> Q; vector<int> abstract(P, 1); for (int i = 0; i < P; ++i) if (find(pi, i) == i && in[i] == 0) Q.push_back(i); // 只有并查集的根节点才能参与广搜 while (!Q.empty()) { int p = Q.front(); Q.pop_front(); for (int q : G[p]) { abstract[q] = max(abstract[q], abstract[p] + 1); if (--in[q] == 0) Q.push_back(q); } } vector<vector<int>> ans(M, vector<int>(N)); // 构造结果 for (int i = 0; i < M; ++i) for (int j = 0; j < N; ++j) ans[i][j] = abstract[find(pi, i*N + j)]; // 根节点的结果就是这个元素的结果