day12b.cpp (3262B)
1 #include <iostream> 2 #include <cstdint> 3 #include <algorithm> 4 #include <string> 5 #include <string_view> 6 #include <vector> 7 #include <set> 8 using namespace std; 9 10 class Direction { 11 public: 12 const int U, R; 13 14 Direction(const int i, const int j) : U{ i }, R{ j } {} 15 16 Direction turnright() const { 17 return turn(-1, 0); 18 } 19 20 Direction turnleft() const { 21 return turn(1, 0); 22 } 23 24 bool operator<(const Direction& d) const { // For set<Direction> 25 return this->U < d.U || (this->U == d.U && this->R < d.R); 26 } 27 private: 28 Direction turn(int64_t sin, int64_t cos) const { 29 return Direction(cos * U - sin * R, sin * U + cos * R); 30 } 31 }; 32 33 class Position { 34 public: 35 int64_t i, j; 36 37 Position(int64_t a, int64_t b) : i{a}, j{b} {} 38 39 Position step(const Direction d) const { 40 return Position(i+d.U, j+d.R); 41 } 42 }; 43 44 const Direction all_directions[] = { 45 Direction(1, 0), Direction(-1, 0), Direction(0, 1), Direction(0, -1) 46 }; 47 48 class Board { 49 public: 50 int64_t N, M; 51 vector<int64_t> region_area; 52 53 Board(const vector<string>& lines) : 54 N{static_cast<int64_t>(lines.size())}, 55 M{static_cast<int64_t>(lines[0].size())}, 56 region_area(M*N), cells(M*N), region(M*N), visited(M*N) 57 { 58 for (int64_t i = 0; i < N; i++) { 59 for (int64_t j = 0; j < M; j++) { 60 region[M*i+j] = -1; 61 cells[M*i+j] = lines[i][j]; 62 } 63 } 64 } 65 66 char& operator[](const Position p) { 67 if (const auto c = coord(p); c == -1) 68 return out_of_bound; 69 else 70 return cells[c]; 71 } 72 73 int64_t& reg(const Position p) { 74 if (const auto c = coord(p); c == -1) 75 return out_of_region; 76 else 77 return region[c]; 78 } 79 80 void fill(const Position p, const int64_t r) { 81 reg(p) = r; 82 region_area[r]++; 83 for (const auto d : all_directions) 84 if (auto q = p.step(d); 85 (*this)[q] == (*this)[p] && reg(q) != r) 86 fill(q, r); 87 } 88 89 int64_t compute_perim(int64_t r) { 90 int count = 0; 91 for (Position p(0, 0); p.i < N; p.i++) 92 for (p.j = 0; p.j < M; p.j++) 93 for (Direction d : all_directions) 94 if (reg(p) == r && reg(p.step(d)) != r) 95 count += walk(p, d); 96 97 return count; 98 } 99 100 private: 101 char out_of_bound = '$'; 102 int64_t out_of_region = -1; 103 104 vector<char> cells; 105 vector<int64_t> region; 106 vector<set<Direction>> visited; 107 108 int64_t coord(const Position p) const { 109 auto [i, j] = p; 110 return i >= N || i < 0 || j >= M || j < 0 ? -1 : M * i + j; 111 } 112 113 bool is_visited(const Position p, const Direction d) const { 114 if (auto c = coord(p); c == -1) 115 return false; 116 else 117 return visited[c].count(d) > 0; 118 } 119 120 void set_visited(const Position p, const Direction d) { 121 if (auto c = coord(p); c != -1) 122 visited[c].insert(d); 123 } 124 125 int64_t walk(const Position p, const Direction d) { 126 const auto r = reg(p); 127 for (auto q = p; reg(q) == r && reg(q.step(d)) != r; 128 q = q.step(d.turnleft())) { 129 if (is_visited(q, d)) 130 return 0; 131 set_visited(q, d); 132 } 133 134 return 1; 135 } 136 }; 137 138 int main() { 139 string line; 140 vector<string> lines; 141 while (getline(cin, line)) 142 lines.push_back(line); 143 144 Board board(lines); 145 146 int64_t r = 0; 147 for (Position p(0, 0); p.i < board.N; p.i++) 148 for (p.j = 0; p.j < board.M; p.j++) 149 if (board.reg(p) == -1) 150 board.fill(p, r++); 151 152 int64_t tot = 0; 153 for (int64_t i = 0; i < r; i++) 154 tot += board.region_area[i] * board.compute_perim(i); 155 156 cout << tot << endl; 157 158 return 0; 159 }