Submission #46166606
Source Code Expand
#include <set>
#include <vector>
#include <utility>
#include <cassert>
#include <iostream>
#define DEBUG(x) x
#define INFO(x) DEBUG(std::cerr << x << std::endl)
#define snap(var) DEBUG(std::cerr << "[snap] " << #var << " = " << (var) << std::endl)
#define snap_msg(msg, var) DEBUG(std::cerr << "[snap:" << (msg) << "] " << #var << " = " << (var) << std::endl)
#define assert_equal(x, y) assert_eq(x, y, #x " == " #y " is not satisfied!")
///---------------------------------------------------------------------
// utility
struct Point {
int i;
int j;
Point() : i(0), j(0) {}
Point(int x, int y) : i(x), j(y) {}
};
template<typename T>
using Row = std::vector<T>;
template<typename T>
using Grid = std::vector<Row<T>>;
bool operator<(const Point& p, const Point& q){
return p.j * 4 + p.i < q.j * 4 + q.i;
}
bool operator==(const Point& p, const Point& q){
return p.i == q.i and p.j == q.j;
}
std::ostream& operator<<(std::ostream& os, const Grid<char>& g) {
os << std::endl;
for (const Row<char>& r : g) {
for (const char c : r) { os << c; }
os << std::endl;
}
return os;
}
std::ostream& operator<<(std::ostream& os, const Point& p) {
return os << "(" << p.i << ", " << p.j << ")";
}
std::ostream& operator<<(std::ostream& os, const std::set<Point>& g) {
os << std::endl;
for (const Point& r : g) {
os << r << ", ";
os << std::endl;
}
return os;
}
template<typename T1, typename T2>
std::ostream& operator<<(std::ostream& os, const std::pair<T1, T2> points) {
return os << "[" << points.first << ", " << points.second << "]";
}
template<typename T>
void assert_eq(const T& a, const T& b, const char* str) {
if (a != b) {
std::cerr << str << std::endl;
snap(a);
snap(b);
assert(0);
}
}
// utility
///---------------------------------------------------------------------
std::set<Point> convert_grid_to_set(const Grid<char>& grid){
std::set<Point> placed_points_set;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (grid[i][j] == '#') {
placed_points_set.insert({i, j});
}
}
}
return placed_points_set;
}
std::set<Point> shift(const std::set<Point>& before, const Point& delta) {
std::set<Point> after;
for (const Point& p : before) {
after.insert({p.i + delta.i, p.j + delta.j});
}
return after;
}
std::set<Point> shift_to_left(const std::set<Point>& before){
Point min{3, 3};
for (const Point& p:before) {
min.i = std::min(p.i, min.i);
min.j = std::min(p.j, min.j);
}
return shift(before, {-min.i, -min.j});
}
std::set<Point> rotate90deg(const std::set<Point>& before){
std::set<Point> after;
for (const auto point:before) {
after.insert({3 - point.j, point.i});
}
return after;
}
std::pair<Point, Point> bounding_box(const std::set<Point>& board) {
Point min{3, 3}, max{-1, -1};
for (const Point& p:board){
min.i = std::min(p.i, min.i);
min.j = std::min(p.j, min.j);
max.i = std::max(p.i, max.i);
max.j = std::max(p.j, max.j);
}
return {min, max};
}
bool is_valid(const std::set<Point>& board) {
// 領域から外れていないか
const auto [min, max] = bounding_box(board);
if (
min.i < 0 or min.j < 0 or
max.i > 3 or max.j > 3
) { return false; }
// ここにsetを使う意味がある。 (1)
return board.size() == 16;
}
/// @brief ポリオミノpolyomino_pointsを位置placed_pointに置いた時に、条件を満たしうるかを深さ優先探索によって探索する。
/// @param board -- 参照をとっていない点に注意; placed_points_num番目のポリオミノを置いた時のボードの状況を示す。
bool possible_proper_placing(
std::set<Point> board,
const std::set<Point>& polyomino_points,
const std::vector<std::set<Point>>& polyominos,
const int placed_poly_number
){
// ここにsetを使う意味がある。 (2)
for (const auto& point : polyomino_points) {
// 外側に置かれている場合はfalse
if (point.i < 0 or 4 <= point.i) { return false; }
if (point.j < 0 or 4 <= point.j) { return false; }
// すでにブロックが置かれていた場合はfalse
if (board.count(point) > 0) { return false; }
board.insert(point);
}
// 全てのポリオミノを置いているときは、その判定が正しいか判定する
if (placed_poly_number == 2) { return is_valid(board); }
// 右端に正規化しているので、16マスの置き方を走査すれば十分
for (int i = 0; i < 4; i++){
for (int j = 0; j < 4; j++){
// 回転4方向を探索する
std::set<Point> rotated_polyomino = shift(polyominos[placed_poly_number + 1], {i, j});
for (int r = 0; r < 4; r++) {
// 可能性があったなら、上の枝にそのことを通知する。
if (possible_proper_placing(board, rotated_polyomino, polyominos, placed_poly_number + 1)) {
return true;
}
// 公式解答参照
rotated_polyomino = rotate90deg(rotated_polyomino);
}
}
}
return false;
}
///---------------------------------------------------------------------
// テスト
void test(){
{
std::set<Point> points = {
{1, 2},
{0, 0},
};
const auto converted1 = std::set<Point>{Point(1, 1), Point(3, 0)};
assert_equal(rotate90deg(points), converted1);
const auto converted2 = std::pair<Point, Point>{Point(0, 0), Point(1, 2)};
assert_equal(bounding_box(points), converted2);
}
{
std::set<Point> points = {
{1, 2},
{2, 1},
};
const auto converted = std::set<Point>{Point(0, 1), Point(1, 0)};
assert_equal(shift_to_left(points), converted);
}
{
std::set<Point> points = {
{0, 0}, {0, 1}, {0, 2}, {0, 3},
{1, 0}, {1, 1}, {1, 2}, {1, 3},
{2, 0}, {2, 1}, {2, 2}, {2, 3},
{3, 0}, {3, 1}, {3, 2}, {3, 3},
};
assert_equal(is_valid(points), true);
}
{
std::set<Point> points = {
{0, 0}, {0, 1}, {0, 2}, {0, 3},
{1, 0}, {1, 1}, {1, 2}, {1, 3},
{2, 0}, {2, 1}, {2, 2}, {2, 3},
{3, 0}, {3, 1}, {3, 2}, {3, 3},
{3, 4}
};
assert_equal(is_valid(points), false);
}
}
///---------------------------------------------------------------------
int main(){
test();
std::vector<Grid<char>> polyominos(3,
Grid<char>(4, Row<char>(4))
);
for (int p = 0; p < 3; p++) {
Grid<char>& polyomino = polyominos[p];
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
std::cin >> polyomino[i][j];
}
}
}
snap(polyominos[0]);
snap(polyominos[1]);
snap(polyominos[2]);
std::vector<std::set<Point>> pointsets = {
shift_to_left(convert_grid_to_set(polyominos[0])),
shift_to_left(convert_grid_to_set(polyominos[1])),
shift_to_left(convert_grid_to_set(polyominos[2])),
};
assert(pointsets.size() == 3);
std::set<Point> board;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (possible_proper_placing(board, shift(pointsets[0], {i, j}), pointsets, 0)) {
std::cout << "Yes" << std::endl;
return 0;
}
}
}
std::cout << "No" << std::endl;
return 0;
}
Submission Info
Submission Time |
|
Task |
D - Polyomino |
User |
Appbird |
Language |
C++ 20 (gcc 12.2) |
Score |
400 |
Code Size |
8046 Byte |
Status |
AC |
Exec Time |
8 ms |
Memory |
3648 KiB |
Judge Result
Set Name |
Sample |
All |
Score / Max Score |
0 / 0 |
400 / 400 |
Status |
|
|
Set Name |
Test Cases |
Sample |
00_sample_00.txt, 00_sample_01.txt, 00_sample_02.txt, 00_sample_03.txt, 00_sample_04.txt, 00_sample_05.txt |
All |
00_sample_00.txt, 00_sample_01.txt, 00_sample_02.txt, 00_sample_03.txt, 00_sample_04.txt, 00_sample_05.txt, 01_random_00.txt, 01_random_01.txt, 01_random_02.txt, 01_random_03.txt, 01_random_04.txt, 01_random_05.txt, 01_random_06.txt, 01_random_07.txt, 01_random_08.txt, 01_random_09.txt, 01_random_10.txt, 01_random_11.txt, 01_random_12.txt, 01_random_13.txt, 01_random_14.txt, 01_random_15.txt, 01_random_16.txt, 01_random_17.txt, 01_random_18.txt, 01_random_19.txt, 01_random_20.txt, 01_random_21.txt, 01_random_22.txt, 01_random_23.txt, 01_random_24.txt, 01_random_25.txt, 01_random_26.txt, 01_random_27.txt, 01_random_28.txt, 01_random_29.txt, 01_random_30.txt, 01_random_31.txt, 01_random_32.txt, 02_corner_00.txt, 02_corner_01.txt, 02_corner_02.txt |
Case Name |
Status |
Exec Time |
Memory |
00_sample_00.txt |
AC |
1 ms |
3380 KiB |
00_sample_01.txt |
AC |
1 ms |
3540 KiB |
00_sample_02.txt |
AC |
1 ms |
3460 KiB |
00_sample_03.txt |
AC |
8 ms |
3452 KiB |
00_sample_04.txt |
AC |
1 ms |
3448 KiB |
00_sample_05.txt |
AC |
1 ms |
3468 KiB |
01_random_00.txt |
AC |
2 ms |
3460 KiB |
01_random_01.txt |
AC |
2 ms |
3604 KiB |
01_random_02.txt |
AC |
1 ms |
3476 KiB |
01_random_03.txt |
AC |
2 ms |
3452 KiB |
01_random_04.txt |
AC |
1 ms |
3548 KiB |
01_random_05.txt |
AC |
1 ms |
3460 KiB |
01_random_06.txt |
AC |
1 ms |
3608 KiB |
01_random_07.txt |
AC |
1 ms |
3608 KiB |
01_random_08.txt |
AC |
2 ms |
3476 KiB |
01_random_09.txt |
AC |
1 ms |
3648 KiB |
01_random_10.txt |
AC |
2 ms |
3472 KiB |
01_random_11.txt |
AC |
1 ms |
3604 KiB |
01_random_12.txt |
AC |
2 ms |
3472 KiB |
01_random_13.txt |
AC |
1 ms |
3476 KiB |
01_random_14.txt |
AC |
1 ms |
3608 KiB |
01_random_15.txt |
AC |
1 ms |
3520 KiB |
01_random_16.txt |
AC |
4 ms |
3476 KiB |
01_random_17.txt |
AC |
1 ms |
3644 KiB |
01_random_18.txt |
AC |
1 ms |
3456 KiB |
01_random_19.txt |
AC |
1 ms |
3452 KiB |
01_random_20.txt |
AC |
1 ms |
3456 KiB |
01_random_21.txt |
AC |
1 ms |
3608 KiB |
01_random_22.txt |
AC |
1 ms |
3472 KiB |
01_random_23.txt |
AC |
1 ms |
3484 KiB |
01_random_24.txt |
AC |
2 ms |
3488 KiB |
01_random_25.txt |
AC |
1 ms |
3476 KiB |
01_random_26.txt |
AC |
3 ms |
3456 KiB |
01_random_27.txt |
AC |
1 ms |
3484 KiB |
01_random_28.txt |
AC |
1 ms |
3552 KiB |
01_random_29.txt |
AC |
2 ms |
3468 KiB |
01_random_30.txt |
AC |
1 ms |
3476 KiB |
01_random_31.txt |
AC |
2 ms |
3468 KiB |
01_random_32.txt |
AC |
2 ms |
3516 KiB |
02_corner_00.txt |
AC |
1 ms |
3468 KiB |
02_corner_01.txt |
AC |
1 ms |
3480 KiB |
02_corner_02.txt |
AC |
1 ms |
3456 KiB |