├── README └── NumberLink ├── sample_input ├── sample_output └── numberlink_solver_v1.cc /README: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /NumberLink/sample_input: -------------------------------------------------------------------------------- 1 | 10 10 2 | 0 0 0 0 0 0 0 0 0 1 3 | 0 0 2 3 0 0 0 0 4 0 4 | 0 0 5 6 0 0 0 0 0 0 5 | 0 0 0 0 0 0 0 0 0 0 6 | 0 0 0 0 1 0 0 0 0 0 7 | 0 0 0 0 0 0 0 0 0 0 8 | 0 0 0 0 0 0 0 0 0 0 9 | 0 0 0 5 0 0 7 6 0 0 10 | 0 0 2 7 0 0 4 3 0 0 11 | 0 0 0 0 0 0 0 0 0 0 12 | 13 | 10 10 14 | 1 2 1 3 0 0 0 0 0 0 15 | 0 0 0 0 0 5 0 0 0 0 16 | 0 0 0 0 0 0 0 0 0 0 17 | 0 0 0 0 0 0 6 0 0 0 18 | 0 0 0 0 0 0 0 0 0 0 19 | 0 2 0 0 0 0 0 0 0 0 20 | 0 0 0 0 0 0 0 0 0 0 21 | 0 0 0 0 4 7 0 0 0 0 22 | 0 6 0 0 0 0 0 7 5 4 23 | 0 0 0 0 0 0 0 0 0 3 24 | 25 | 10 10 26 | 1 2 1 3 0 0 0 0 0 0 27 | 0 0 0 0 0 5 0 0 0 0 28 | 0 0 0 0 0 0 0 0 0 0 29 | 0 0 0 0 0 0 0 0 0 0 30 | 0 0 0 0 0 0 0 0 0 0 31 | 0 2 0 0 0 0 0 0 0 0 32 | 0 0 0 0 0 0 0 0 0 0 33 | 0 0 0 0 4 0 0 0 0 0 34 | 0 0 0 0 0 0 0 0 5 4 35 | 0 0 0 0 0 0 0 0 0 3 36 | 37 | 10 10 38 | 0 0 0 0 0 0 0 0 0 1 39 | 0 0 0 0 0 0 0 0 0 0 40 | 0 0 0 0 0 0 0 0 0 0 41 | 0 0 0 0 0 0 0 0 0 0 42 | 0 0 0 0 0 0 0 0 0 0 43 | 0 0 0 0 0 0 0 0 0 0 44 | 0 0 0 0 0 0 0 0 0 0 45 | 0 0 0 0 0 0 0 0 0 0 46 | 0 0 0 0 0 0 0 0 0 0 47 | 1 0 0 0 0 0 0 0 0 0 48 | 49 | 10 2 50 | 1 0 0 0 0 0 0 0 0 1 51 | 0 0 0 0 0 0 0 0 0 0 52 | 53 | 3 2 54 | 1 0 1 55 | 0 0 0 56 | 57 | 0 0 58 | -------------------------------------------------------------------------------- /NumberLink/sample_output: -------------------------------------------------------------------------------- 1 | +---+---+---+---+---+---+---+---+---+---+ 2 | | ###################################001| 3 | + # + + + + + + + + + + 4 | | # ###002 003############### 004### | 5 | + # + # + + + + + + # + + # + 6 | | # # 005 006########### ##### # | 7 | + # + # + # + + + + # + + # + # + 8 | | # # # ######### ##### # # | 9 | + # + # + # + # + + # + + # + # + # + 10 | | # # # # 001 ##### # # # | 11 | + # + # + # + # + # + + # + # + # + # + 12 | | # # # # ##### # # # # | 13 | + # + # + # + # + + # + # + # + # + # + 14 | | # # # ##### # # # # # | 15 | + # + # + # + + # + # + # + # + # + # + 16 | | # # ###005 # # 007 006 # # | 17 | + # + # + + + # + # + + + # + # + 18 | | # ###002 007### # 004 003### # | 19 | + # + + + + + # + # + + + # + 20 | | ##################### ############# | 21 | +---+---+---+---+---+---+---+---+---+---+ 22 | # of solutions: 1 23 | +---+---+---+---+---+---+---+---+---+---+ 24 | |001 002 001 003 ##################### | 25 | + # + # + # + # + # + + + + + # + 26 | | # # # # # 005########### # | 27 | + # + # + # + # + # + + + + # + # + 28 | | # # # # # ######### # # | 29 | + # + # + # + # + # + # + + # + # + # + 30 | | # # # # # # 006 # # # | 31 | + # + # + # + # + # + # + # + # + # + # + 32 | | # # # # # # # # # # | 33 | + # + # + # + # + # + # + # + # + # + # + 34 | | # 002 # # # # # # # # | 35 | + # + + # + # + # + # + # + # + # + # + 36 | | ######### # # # # # # # | 37 | + + + + # + # + # + # + # + # + # + 38 | | ############# 004 007 # # # # | 39 | + # + + + + + + # + # + # + # + 40 | | # 006################### 007 005 004| 41 | + # + + + + + + + + + + 42 | | ###################################003| 43 | +---+---+---+---+---+---+---+---+---+---+ 44 | # of solutions: 1 45 | +---+---+---+---+---+---+---+---+---+---+ 46 | |001 002 001 003 ######### | 47 | + # + # + # + # + # + + # + + + + 48 | | # # # # # 005 # | 49 | + # + # + # + # + # + # + # + + + + 50 | | # # # # # # # | 51 | + # + # + # + # + # + # + # + + + + 52 | | # # # # # # # | 53 | + # + # + # + # + # + # + # + + + + 54 | | # # # # # # # | 55 | + # + # + # + # + # + # + # + + + + 56 | | # 002 # # # # # | 57 | + # + + # + # + # + # + # + + + + 58 | | # # # # # # | 59 | + # + + # + # + # + # + # + + + + 60 | | # # # 004 # ############# | 61 | + # + + # + # + + # + + + + # + 62 | | # # # ###########005 004| 63 | + # + + # + # + + + + + + + 64 | | ######### #######################003| 65 | +---+---+---+---+---+---+---+---+---+---+ 66 | # of solutions: 21022680789 67 | +---+---+---+---+---+---+---+---+---+---+ 68 | | 001| 69 | + + + + + + + + + + # + 70 | | # | 71 | + + + + + + + + + + # + 72 | | # | 73 | + + + + + + + + + + # + 74 | | # | 75 | + + + + + + + + + + # + 76 | | # | 77 | + + + + + + + + + + # + 78 | | # | 79 | + + + + + + + + + + # + 80 | | # | 81 | + + + + + + + + + + # + 82 | | # | 83 | + + + + + + + + + + # + 84 | | # | 85 | + + + + + + + + + + # + 86 | |001################################### | 87 | +---+---+---+---+---+---+---+---+---+---+ 88 | # of solutions: 4.1044208702632e+19 89 | +---+---+---+---+---+---+---+---+---+---+ 90 | |001 001| 91 | + # + + + + + + + + + # + 92 | | ##################################### | 93 | +---+---+---+---+---+---+---+---+---+---+ 94 | # of solutions: 512 95 | +---+---+---+ 96 | |001 001| 97 | + # + + # + 98 | | ######### | 99 | +---+---+---+ 100 | # of solutions: 4 101 | -------------------------------------------------------------------------------- /NumberLink/numberlink_solver_v1.cc: -------------------------------------------------------------------------------- 1 | // numberlink_solver - Number Link Solver based on ZDD. 2 | // 3 | // Copyright (C) 2011 Kentaro Imajo. All rights reserved. 4 | // Author: Kentaro Imajo (Twitter: imos) 5 | // 6 | // This program uses special ordered cell keys. From the upper-left-most cell 7 | // to bottom-right-most cell, it traces every cell with diagonal lines from 8 | // upper-right to bottom-left. For 4x4 table, we use the order that is denoted 9 | // in the following table. 10 | // 00 01 03 06 11 | // 02 04 07 10 12 | // 05 08 11 13 13 | // 09 12 14 15 14 | // 15 | // This program inputs some datasets from the standard input. Each dataset 16 | // should have `width' and `height' in this order with a space delimiter in 17 | // the first line, and each of the following height lines should have width 18 | // integers. Zeroes represent blank cells, and one or more represent 19 | // themselves. For the NumberLink problem (the left figure), you should use the 20 | // input (the right figure). 21 | // 22 | // +---+---+---+---+ Standard Input: 23 | // | 1 2 | 4 3 24 | // + + + + + 1 0 0 2 25 | // | 3 1 | 0 3 1 0 26 | // + + + + + 3 2 0 0 27 | // | 3 2 | 28 | // +---+---+---+---+ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | using namespace std; 37 | 38 | bool FLAGS_color = false; 39 | 40 | class NumberLink { 41 | public: 42 | // The type of the number written in a cell 43 | typedef char CellNumber; 44 | // The type of the ID number of a cell 45 | typedef short CellKey; 46 | // The type of a coordinate represented by (y * width + x) 47 | typedef short CellPosition; 48 | // The type of a distance such as width, height, x and y 49 | typedef int Distance; 50 | // The size of the NumberLink task 51 | Distance width_; 52 | Distance height_; 53 | 54 | NumberLink(const Distance width, const Distance height): 55 | width_(width), height_(height), size_((CellKey)width * height), 56 | cell_x_(size_), cell_y_(size_), table_(size_), 57 | keys_(size_), mates_(size_), start_(size_ + 1), 58 | connected_x_(size_), connected_y_(size_), memo_(size_) {} 59 | 60 | void Initialize() { 61 | // Initialize mates 62 | for (CellKey cell_key = 0; cell_key < size_; cell_key++) { 63 | mates_[cell_key] = cell_key; 64 | } 65 | 66 | // Generates references: (x, y) <=> CellKey 67 | Distance x = 0, y = 0; 68 | CellKey cell_key = 0; 69 | while (true) { 70 | CellPosition position = (CellPosition)y * width_ + x; 71 | cell_x_[cell_key] = x; 72 | cell_y_[cell_key] = y; 73 | keys_[position] = cell_key; 74 | cell_key++; 75 | if (cell_key == size_) break; 76 | do { 77 | x--; 78 | y++; 79 | if (x < 0) { 80 | x = y; 81 | y = 0; 82 | } 83 | } while (x < 0 || width_ <= x || y < 0 || height_ <= y); 84 | } 85 | 86 | // Pre-compute CellKey to look back for every cell 87 | for (CellKey i = 0; i < size_; i++) { 88 | Distance x = cell_x_[i], y = cell_y_[i]; 89 | start_[i] = 0 < y ? GetCellKey(x, y - 1) : 90 | (0 < x ? GetCellKey(x - 1, y) : 0); 91 | } 92 | // For a guard 93 | start_[size_] = size_; 94 | } 95 | 96 | // Returns the reference of the number written in the cell (x,y). 97 | CellNumber& Cell(const Distance x, const Distance y) 98 | { return table_[GetCellKey(x, y)]; } 99 | // Returns the key of the special order for the coordinate (x,y). 100 | CellKey GetCellKey(const Distance x, const Distance y) const 101 | { return keys_[(CellPosition)y * width_ + x]; } 102 | 103 | double Solve(const CellKey cell_key = 0) { 104 | if (cell_key == 0) solved_ = false; 105 | // See the newly fixed cells 106 | if (0 < cell_key) { 107 | for (CellKey hidden = start_[cell_key - 1]; 108 | hidden < start_[cell_key]; hidden++) { 109 | if (table_[hidden] == 0) { 110 | // Return if the empty cell has an end 111 | if (mates_[hidden] != -1 && mates_[hidden] != hidden) return 0.0; 112 | } else { 113 | // Return if the numbered cell has no line 114 | if (mates_[hidden] == hidden) return 0.0; 115 | } 116 | } 117 | } 118 | // If all the cells are filled 119 | if (cell_key == size_) { 120 | if (!solved_) { 121 | Print(); 122 | solved_ = true; 123 | } 124 | return 1.0; 125 | } 126 | 127 | // Connect successive cells if this sequence of mates has not been seen 128 | const vector mate_tuple(mates_.begin() + start_[cell_key], 129 | mates_.begin() + cell_key); 130 | const Hash mate_hash = GetHash(mate_tuple); 131 | if (!memo_[cell_key].count(mate_hash)) { 132 | memo_[cell_key][mate_hash] = Connect(cell_key); 133 | } 134 | return memo_[cell_key][mate_hash]; 135 | } 136 | 137 | double Connect(const CellKey cell_key) { 138 | double solution_count = 0.0; 139 | Distance x = cell_x_[cell_key], y = cell_y_[cell_key]; 140 | CellKey left_cell_key = -1, up_cell_key = -1; 141 | if (0 < x) left_cell_key = GetCellKey(x - 1, y); 142 | if (0 < y) up_cell_key = GetCellKey(x, y - 1); 143 | size_t revert_point = mate_stack_.size(); 144 | // Connect the cell with nothing 145 | solution_count += Solve(cell_key + 1); 146 | // Connect the cell with the upper cell 147 | if (0 <= up_cell_key) { 148 | if (UniteMates(cell_key, up_cell_key)) { 149 | connected_y_[cell_key] = true; 150 | solution_count += Solve(cell_key + 1); 151 | connected_y_[cell_key] = false; 152 | } 153 | RevertMates(revert_point); 154 | } 155 | // Connect the cell with the left cell 156 | if (0 <= left_cell_key) { 157 | if (UniteMates(cell_key, left_cell_key)) { 158 | connected_x_[cell_key] = true; 159 | solution_count += Solve(cell_key + 1); 160 | // Connect the cell with the upper and the left cells 161 | if (0 <= up_cell_key) { 162 | if (UniteMates(cell_key, up_cell_key)) { 163 | connected_y_[cell_key] = true; 164 | solution_count += Solve(cell_key + 1); 165 | connected_y_[cell_key] = false; 166 | } 167 | } 168 | connected_x_[cell_key] = false; 169 | } 170 | RevertMates(revert_point); 171 | } 172 | return solution_count; 173 | } 174 | 175 | void Print() { 176 | for (Distance y = 0; y <= height_; y++) { 177 | for (Distance x = 0; x < width_; x++) { 178 | printf(FLAGS_color ? "\x1b[32m+\x1b[0m" : "+"); 179 | printf((y % height_ == 0) ? 180 | (FLAGS_color ? "\x1b[32m---\x1b[0m" : "---") : 181 | (connected_y_[GetCellKey(x, y)] ? " # " : " ")); 182 | } 183 | puts(FLAGS_color ? "\x1b[32m+\x1b[0m" : "+"); 184 | if (height_ <= y) break; 185 | for (Distance x = 0; x < width_; x++) { 186 | printf(x ? (connected_x_[GetCellKey(x, y)] ? "#" : " ") : 187 | (FLAGS_color ? "\x1b[32m|\x1b[0m" : "|")); 188 | if (table_[GetCellKey(x, y)]) { 189 | printf("%03d", table_[GetCellKey(x, y)]); 190 | } else { 191 | printf(connected_x_[GetCellKey(x, y)] ? "#" : " "); 192 | printf(mates_[GetCellKey(x, y)] == GetCellKey(x, y) ? " " : "#"); 193 | printf((x + 1 < width_ && connected_x_[GetCellKey(x + 1, y)]) 194 | ? "#" : " "); 195 | } 196 | } 197 | puts(FLAGS_color ? "\x1b[32m|\x1b[0m" : "|"); 198 | } 199 | } 200 | 201 | private: 202 | // Hash key to identify a sequence of CellKeys 203 | typedef pair Hash; 204 | // The number of cells on the board 205 | CellKey size_; 206 | // History of modification 207 | stack< pair > mate_stack_; 208 | // Map from a CellKey to a coordinate 209 | vector cell_x_, cell_y_; 210 | // Store the numbers in the cells 211 | vector table_; 212 | vector keys_, mates_, start_; 213 | // Description of links on the board 214 | vector connected_x_, connected_y_; 215 | // Hash table to identify a sequence of CellKeys 216 | vector< map > memo_; 217 | // Flag to know whether the problem has been solved 218 | bool solved_; 219 | 220 | // Get a hash key based on the XorShift algorithm 221 | Hash GetHash(const vector &cell_keys) { 222 | unsigned int x = 123456789, y = 362436069, z = 521288629, w = 88675123; 223 | for (int i = 0; i < (int)cell_keys.size(); i++) { 224 | unsigned int t = (x ^ (x << 11)); x = y; y = z; z = w; 225 | w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)) + (unsigned int)cell_keys[i]; 226 | } 227 | Hash h; 228 | h.first = ((unsigned long long)x << 32) | y; 229 | h.second = ((unsigned long long)z << 32) | w; 230 | return h; 231 | } 232 | 233 | // Change the table of mates in adding the history 234 | int ChangeMates(const CellKey cell_key, const CellKey cell_value) { 235 | int last_stack_size = mate_stack_.size(); 236 | CellKey last_value = mates_[cell_key]; 237 | if (last_value != cell_value) { 238 | mate_stack_.push(make_pair(cell_key, last_value)); 239 | mates_[cell_key] = cell_value; 240 | } 241 | return last_stack_size; 242 | } 243 | 244 | // Revert the table of mates using the history 245 | void RevertMates(const size_t stack_size) { 246 | for (; stack_size < mate_stack_.size(); mate_stack_.pop()) 247 | mates_[mate_stack_.top().first] = mate_stack_.top().second; 248 | } 249 | 250 | // Connects cell_key1 and cell_key2 by a line. Returns false if it cannot 251 | // connect the cells because of constraints. The table of mates must be 252 | // reverted even if the cells cannot be connect correctly. 253 | bool UniteMates(const CellKey cell_key1, const CellKey cell_key2) { 254 | CellKey end1 = mates_[cell_key1], end2 = mates_[cell_key2]; 255 | // Cannot connect any branch 256 | if (end1 == -1 || end2 == -1) return false; 257 | // Avoid making a cycle 258 | if (cell_key1 == end2 && cell_key2 == end1) return false; 259 | // Change states of mates to connect cell_key1 and cell_key2 260 | ChangeMates(cell_key1, -1); 261 | ChangeMates(cell_key2, -1); 262 | ChangeMates(end1, end2); 263 | ChangeMates(end2, end1); 264 | // Check three constraints: 265 | // 1. cell_key1 must not be a branch if cell_key1 is numbered, 266 | // 2. cell_key2 must not be a branch if cell_key2 is numbered, 267 | // 3. Different numbers cannot be connected. 268 | if (mates_[cell_key1] == -1 && 0 < table_[cell_key1]) return false; 269 | if (mates_[cell_key2] == -1 && 0 < table_[cell_key2]) return false; 270 | if (0 < table_[end1] && 0 < table_[end2] && 271 | table_[end1] != table_[end2]) return false; 272 | return true; 273 | } 274 | }; 275 | 276 | void ParseArguments(int *argc, char **argv) { 277 | int arg_pos = 1; 278 | for (int i = 1; i < *argc; i++) { 279 | char *flag = argv[i]; 280 | if (flag[0] == '-' && flag[1] == '-') { 281 | char *key = flag + 2, *value = strstr(key, "="); 282 | if (value) { 283 | *value = 0; 284 | value++; 285 | } 286 | if (strcmp(key, "color") == 0) { 287 | FLAGS_color = true; 288 | } 289 | } else { 290 | argv[arg_pos] = argv[i]; 291 | arg_pos++; 292 | } 293 | } 294 | *argc = arg_pos; 295 | } 296 | 297 | int main(int argc, char **argv) { 298 | ParseArguments(&argc, argv); 299 | int width, height; 300 | // Until the input ends or 0x0 is given 301 | while (2 == scanf("%d%d", &width, &height) && width && height) { 302 | NumberLink nl((int)width, (int)height); 303 | nl.Initialize(); 304 | for (int y = 0; y < nl.height_; y++) { 305 | for (int x = 0; x < nl.width_; x++) { 306 | int value; 307 | scanf("%d", &value); 308 | nl.Cell(x, y) = value; 309 | } 310 | } 311 | double solution_count = nl.Solve(); 312 | printf("# of solutions: "); 313 | // Change an output format because of the precision of the double type 314 | if (solution_count < 1e13) { 315 | printf("%.0f\n", solution_count); 316 | } else { 317 | printf("%.13e\n", solution_count); 318 | } 319 | } 320 | return 0; 321 | } 322 | --------------------------------------------------------------------------------