POJ1052 Plato's Blocks
题目来源:http://poj.org/problem?id=1052
题目大意:
把1*1*1的小立方体通过粘接相邻面组成大的立方体的形状。如下图所示:
一层一层地堆叠,立方体从三个方向的投影会分别形成三个字母的形状:"E" "G" "B"
科学家们想知道哪些投影形状的组合是可能出现的。写一个程序判断给定的投影图形组合是否可能出现。
输入:由一系列数据集组成。每个用例第一行为一个整数n(1<=n<=20),表示大立方体的边长。接下来的3*n行为给出的投影图形。每n行表示一个面的投影,'X'表示产生了影子,'-'表示光线穿过。n为0时表示输入结束。
输出:如果给出的组合可能产生,输出:Valid set of patterns 否则输出 Impossible combination 格式见sample.
Sample Input
5 XXXXX X---- X--XX X---X XXXXX XXXXX X---- XXXXX X---- XXXXX XXXXX X---X XXXX- X---X XXXXX 3 X-- -X- --X XX- XXX -XX -XX XXX XX- 0
Sample Output
Data set 1: Valid set of patterns Data set 2: Impossible combination
本题也属于模拟吧。首先需要把题目看懂。
首先,对于每个给出的投影图像,可能对应8种情况:通过旋转和镜像的变换得到。那么三个面总共有8*8*8种组合,枚举所有的组合,能找到符合条件的立方体能说明组合是可能出现的,否则不可能。
通过正向构造立方体比较麻烦,可以用“逆向”的方法。具体来说,首先根据给定的立方体大小,首先初始化一个完整的立方体。然后对于投影图形中被光线穿透的格子,“挖”去立方体对应的部分。
然而对每个面这样处理后得到的残留图形并不一定还能形成给定的三个投影,所以需要检验。除了检验投影还要检验它的连通性(dfs)。
代码中循环很多,要小心。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 ////////////////////////////////////////////////////////////////////////// 2 // POJ1052 Plato's Blocks 3 // Memory: 396K Time: 16MS 4 // Language: C++ Result: Accepted 5 ////////////////////////////////////////////////////////////////////////// 6 7 #include <iostream> 8 9 using namespace std; 10 int n; 11 int face[3][8][20][20]; 12 int cube[20][20][20]; 13 int visited[20][20][20]; 14 15 bool input() { 16 cin >> n; 17 if (n == 0) return false; 18 char c; 19 for (int t = 0; t < 3; ++t) { 20 for (int i = 0; i < n; ++i) { 21 for (int j = 0; j < n; ++j) { 22 cin >> c; 23 if (c == 'X') face[t][0][i][j] = 1; 24 else face[t][0][i][j] = 0; 25 } 26 } 27 } 28 return true; 29 } 30 31 void r_m() { 32 //rotation 33 for (int t = 0; t < 3; ++t) { 34 for (int k = 1; k <= 3; ++k) { 35 for (int i = 0; i < n; ++i) { 36 for (int j = 0; j < n; ++j) { 37 face[t][k][i][j] = face[t][k - 1][j][n - i - 1]; 38 } 39 } 40 } 41 } 42 //mirror 43 for (int t = 0; t < 3; ++t) { 44 for (int k = 0; k < 4; ++k) { 45 for (int i = 0; i < n; ++i) { 46 for (int j = 0; j < n; ++j) { 47 face[t][k + 4][i][j] = face[t][k][i][n - j - 1]; 48 } 49 } 50 } 51 } 52 } 53 54 void MakeCube(int a, int b, int c) { 55 for (int i = 0; i < n; ++i) { 56 for (int j = 0; j < n; ++j) { 57 if (face[0][a][i][j] == 0) { 58 for (int k = 0; k < n; ++k) { 59 cube[i][j][k] = 0; 60 } 61 } 62 } 63 } 64 for (int i = 0; i < n; ++i) { 65 for (int j = 0; j < n; ++j) { 66 if (face[1][b][i][j] == 0) { 67 for (int k = 0; k < n; ++k) { 68 cube[k][i][j] = 0; 69 } 70 } 71 } 72 } 73 for (int i = 0; i < n; ++i) { 74 for (int j = 0; j < n; ++j) { 75 if (face[2][c][i][j] == 0) { 76 for (int k = 0; k < n; ++k) { 77 cube[i][k][j] = 0; 78 } 79 } 80 } 81 } 82 } 83 84 bool check(int a, int b, int c) { 85 for (int i = 0; i < n; ++i) { 86 for (int j = 0; j < n; ++j) { 87 if (face[0][a][i][j] == 1) { 88 bool flag = 0; 89 for (int k = 0; k < n; ++k) { 90 if (cube[i][j][k]) { 91 flag = 1; 92 break; 93 } 94 } 95 if (flag == 0) { 96 return false; 97 } 98 } 99 } 100 } 101 for (int i = 0; i < n; ++i) { 102 for (int j = 0; j < n; ++j) { 103 if (face[1][b][i][j] == 1) { 104 bool flag = 0; 105 for (int k = 0; k < n; ++k) { 106 if (cube[k][i][j]) { 107 flag = 1; 108 break; 109 } 110 } 111 if (flag == 0) { 112 return false; 113 } 114 } 115 } 116 } 117 for (int i = 0; i < n; ++i) { 118 for (int j = 0; j < n; ++j) { 119 if (face[2][c][i][j]) { 120 bool flag = 0; 121 for (int k = 0; k < n; ++k) { 122 if (cube[i][k][j]) { 123 flag = 1; 124 break; 125 } 126 } 127 if (flag == 0) { 128 return false; 129 } 130 } 131 } 132 } 133 return true; 134 } 135 136 void dfs(int i, int j, int k) { 137 if (i < 0 || i >= n || j < 0 || j >= n || k < 0 || k >= n) { 138 return ; 139 } 140 if (cube[i][j][k] == 0 || visited[i][j][k] == 1) { 141 return; 142 } 143 visited[i][j][k] = 1; 144 dfs(i - 1, j, k); 145 dfs(i + 1, j, k); 146 dfs(i, j - 1, k); 147 dfs(i, j + 1, k); 148 dfs(i, j, k - 1); 149 dfs(i, j, k + 1); 150 } 151 152 153 bool connectivity() { 154 memset(visited, 0, sizeof(visited)); 155 for (int i = 0; i < n; ++i) { 156 for (int j = 0; j < n; ++j) { 157 if (cube[i][j][0]) { 158 dfs(i, j, 0); 159 for (int a = 0; a < n; ++a) { 160 for (int b = 0; b < n; ++b) { 161 for (int c = 0; c < n; ++c) { 162 if (cube[a][b][c] && visited[a][b][c] == 0) { 163 return false; 164 } 165 } 166 } 167 } 168 return true; 169 } 170 } 171 } 172 } 173 174 bool IsValid() { 175 r_m(); 176 for (int i = 0; i < 8; ++i) { 177 for (int j = 0; j < 8; ++j) { 178 for (int k = 0; k < 8; ++k) { 179 memset(cube, 1, sizeof(cube)); 180 MakeCube(i, j, k); 181 if (check(i, j, k) && connectivity()) { 182 return true; 183 } 184 } 185 } 186 } 187 return false; 188 } 189 190 int main(void) { 191 int case_id = 0; 192 while (input()) { 193 cout << "Data set " << ++case_id << ": "; 194 if (IsValid()) { 195 cout << "Valid set of patterns" << endl; 196 } else { 197 cout << "Impossible combination" << endl; 198 } 199 } 200 system("pause"); 201 return 0; 202 }