Algorithm (Math)
- One key observation is the following.
- Proposition. A board B could be transformed to a chessboard by swapping rows and columns if and only if
- It has two unique columns and two unique rows.
- Each one of the unique columes has evenly splitted 0’s and 1’s. (In the odd dimension case, this translate to the difference between 0’s and 1’s is 1)
- Proof.
- ⇒. Suppose B is transformable. Then the result follows by definition.
- ⇐. We prove the contrapositive.
- Suppose B is not transformable. Then it follows that for any set of transformation applied to B, there would exists an adjacent pair has identical labels. Without loss of generality, we let the label be 1 on column, say B[i][c],B[i+1][c].
- Suppose condition 1 and 2 hold. Then we can apply a set of transformation to evenly distribute the two unique rows of B. Since there are only two rows and row i and row i+1 are not the same by construction, it follows that all of column c os 1, i.e, B[j][c]=1 for all j=1,…,N.
- But then this would result a contradiction because the 1‘0 and 0’s are not evenly splitted.
- Using this observation, is it trivial to come up with an algorithm to check feasibility.
Code
namespace utils::dynamic_bitset {
template <typename set_t = int, typename... Ts, typename std::enable_if_t<std::conjunction_v<std::is_same<int, Ts>...>>* = nullptr>
int flip(set_t mask, Ts... arg) { return ((mask ^= (1 << arg)), ...); }
template <typename set_t = int, typename... Ts, typename std::enable_if_t<std::conjunction_v<std::is_same<int, Ts>...>>* = nullptr>
bool test(set_t mask, Ts... arg) { return ((mask & (1 << arg)) && ...); }
template <typename set_t = int, typename T, typename std::enable_if_t<std::conjunction_v<std::is_same<int, T>>>* = nullptr>
int count_upto(set_t mask, T n) {
int acc = 0;
for (int i = 0; i < n; i++)
if ((mask & (1 << i)) > 0) acc++;
return acc;
};
template <typename set_t = int>
void assign_inplace(set_t* mask, int pos, int n) {
if ((test(*mask, pos) and n == 0)
or (not test(*mask, pos) and n == 1))
*mask = flip(*mask, pos);
}
}
class Solution {
public:
int movesToChessboard(vector<vector<int>>& board) {
#define ALL(x) begin(x), end(x)
using namespace utils::dynamic_bitset;
const int N = size(board);
auto get_column = [&](int i) {
auto result {vector<int>{}};
for (int r = 0; r < N; ++r)
result.emplace_back(board[r][i]);
return result;
};
auto bit_representation = [&](const vector<int>& x) {
int acc = 0;
for (int i = 0; i < size(x); ++i)
assign_inplace(&acc, i, x[i]);
return acc;
};
const auto row_bitmap = [&](vector<int> self = {}) {
self.resize(N);
for (int r = 0; r < N; ++r)
self[r] = bit_representation(board[r]);
return self;
}();
const auto col_bitmap = [&](vector<int> self = {}) {
self.resize(N);
for (int c = 0; c < N; ++c) {
self[c] = bit_representation(get_column(c));
}
return self;
}();
auto admissable_config = [&](int input) -> optional<vector<int>> {
const auto one_count = count_upto(input, N);
const auto head_one = [&](int acc = 0) {
for (int i = 0; i < N; i += 2)
assign_inplace(&acc, i, 1);
return acc;
}();
const auto head_zero = [&](int acc = 0) {
for (int i = 1; i < N; i += 2)
assign_inplace(&acc, i, 1);
return acc;
}();
auto result = optional<vector<int>>{};
if (std::abs(one_count - (N - one_count)) > 1)
result = std::nullopt;
else if (N % 2 == 1 and one_count > N - one_count)
result.emplace({head_one});
else if (N % 2 == 1 and one_count < N - one_count)
result.emplace({head_zero});
else if (N % 2 == 0 and std::abs(one_count - (N - one_count)) == 0)
result.emplace({head_zero, head_one});
return result;
};
auto cost = [&](int to, int from) { return count_upto(to ^ from, N) / 2; };
const int solution = [&] {
if (size(unordered_set<int>(ALL(col_bitmap))) != 2 or size(unordered_set<int>(ALL(row_bitmap))) != 2)
return -1;
else {
const auto row_config = admissable_config(row_bitmap[0]);
const auto col_config = admissable_config(col_bitmap[0]);
if (not row_config or not col_config)
return -1;
else {
const auto row_cost = [&](vector<int> self = {}) {
for (const auto x : row_config.value())
self.emplace_back(cost(x, row_bitmap[0]));
return self;
}();
const auto col_cost = [&](vector<int> self = {}) {
for (const auto x : col_config.value())
self.emplace_back(cost(x, col_bitmap[0]));
return self;
}();
return *min_element(ALL(row_cost)) + *min_element(ALL(col_cost));
}
}
}();
return solution;
}
};
大佬,请收下我的膝盖
不敢不敢