UVA - 806 Spatial Structures
/* 题目链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=747 白书对此题的评价: 本题有一定实际意义,而且需要注意细节,建议读者一试 ---------------------------------------------------- 参考的题解: http://blog.csdn.net/crazysillynerd/article/details/43882593 //这个博主的题目解释,可谓是相当详细。在看书上的中文题意以后,我其实是觉得有些细节没有明白。再上 uva 看英文原题时,仍然不太明白。最后是看到这个博主的解释,我才豁然开朗... */
/* 借鉴思路于: http://blog.csdn.net/u014800748/article/details/44866133 */ #include <iostream> #include <stack> #include <vector> #include <cstring> #include <algorithm> #define rep(i, j, n) for (int i = j; i < (n); i++) #define Clean(i, j) memset(i, j, sizeof(i)) using namespace std; const int N = 64 + 5; char g[N][N]; vector<int>code; int n; struct Node { int color; //黑色或白色 int dir; // 表示方向,不同的方向 (NW、NE、SW、SE)有不同的权重 }node[N * N]; void encode(int r, int c, int w, int dir, int &id) { //(r, c)表示起点坐标,w表示宽度,dir表示编码后的方向,id表示结点编号(传引用使得,如果该区域确实可以用一个结点来表示,那么下次再标结点时,标号就从 id+1 开始) int ok = 1; char ch = g[r][c]; rep(i, r, r + w) rep(j, c, c + w) if (g[i][j] != ch) { ok = 0; //表示这个区域里有不同颜色的情况,这个区域必须划分四等分 break; } if (ok) //表示该区域同色,可作为一个结点处理 { node[id].color = (ch == '0' ? 0 : 1); int x = dir, k = 1; stack<int> s; // 利用栈来实现五进制向十进制的转换 while (x > 0) { s.push(x % 10); x /= 10; } while ( !s.empty() ) { node[id].dir += s.top() * k; s.pop(); k *= 5; } id++; } else //该区域有不同色,则分为四个区域,递归编码 { encode ( r, c, w / 2, dir * 10 + 1, id ); encode ( r, c + w / 2, w / 2, dir * 10 + 2, id ); encode ( r + w / 2, c, w / 2, dir * 10 + 3, id ); encode ( r + w / 2, c + w / 2, w / 2, dir * 10 + 4, id); } } void draw (int r, int c, int w) { rep(i, r, r + w) rep(j, c, c + w) g[i][j] = '*'; } void decode(vector<int> s) { int size = (int)s.size(); rep(i, 0, size) { int x = s[i], k = 1; node[i].color = 1; while (x > 0) //解码路径,低位是靠近树根的路径 { node[i].dir += ( x % 5 ) * k; x /= 5, k *= 10; } } rep(i, 0, size) { int dir = node[i].dir; int r = 0, c = 0, w = n; while (dir > 0) //沿路径找区域 { int x = dir % 10; //越是靠近各位的位,对应的是越靠近根节点的路径,从根出发,所以从个位开始 w /= 2, dir /= 10; //注意此时的 w 已经减半了,所以后面累加到 r 或是 c 上时,不必再减半 if (x == 2) c += w; else if (x == 3) r += w; else if (x == 4) c += w, r += w; } draw(r, c, w); } rep(i, 0, n) rep(j, 0, n) if (g[i][j] != '*') g[i][j] = '.'; rep(i, 0, n) puts(g[i]); } void solve() { int kase = 0; while ( scanf("%d", &n), n ) { Clean(g, '\0'); Clean(node, 0); if (kase) printf("\n"); printf("Image %d\n", ++kase); if (n > 0) { rep(i, 0, n) scanf("%s", g[i]); int id = 1; encode(0, 0, n, 0, id); //编码整张图 vector<int> ans; rep(i, 1, id) if (node[i].color == 1) ans.push_back(node[i].dir); sort(ans.begin(), ans.end()); rep(i, 0, (int)ans.size()) { printf("%d", ans[i]); if ( (i + 1) % 12 == 0 || i == (int)ans.size() - 1) printf("\n"); else printf(" "); } printf("Total number of black nodes = %d\n", (int)ans.size()); } else { code.clear(); n = -n; int x; while (scanf("%d", &x) && x != -1) code.push_back(x); decode(code); //解码,画图 } } } int main() { solve(); return 0; }
/* 查阅的其他资料: https://zhidao.baidu.com/question/578232457.html http://blog.csdn.net/xingjiarong/article/details/47282817 */