UVa 806 - Spatial Structures

时间限制:3.000秒

题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=839&page=show_problem&problem=747


  又是一道跟树有关的数据结构的题,要求实现的是黑白图像点阵表示和路径表示之间的相互转换。

  黑白图像向路径表示的转换方法如下,需要先把点阵图转换成一棵树,首先对黑白图像做如下划分:

  

  也就是说,如果某一大区域所有色块颜色是相同的,那么这一个大区域就算作一块,如果不同,则将其划分成四个小区域,然后重复上述步骤递归进行直到所有区域的颜色相同为止。然后根据上面划分的区域建树,小区域作为大区域的子树:

  

  然后对于每一个黑色的区域,也就是上面树上是黑色的结点,将其从叶子结点到根节点的路径表示出来,每一个非叶子结点的四条路权值分别为1、2、3、4,例如,对于编号为4的结点,路径就为32,编号为5的结点路径就为43,以此类推。然后将这些得到的路径作为一个五进制的数,然后将其转换为十进制的数。例如编号为4的结点对应的数就是17,编号为5的结点对应的数就是23,以此类推。最后将所有黑色结点对应的数字排序后得到一个数字序列,即为该黑白图像的路径表示。例如,上面的黑白图像得到的路径表示即为:9,14,17,22,23,44,63,69,88,94,113。

  而路径表示向黑白图像的转换则是反过来,将数字序列转换为黑白的点阵图。


  题目也不算难,求路径表示按照题意逐步转换就能够得到结果,而求点阵表示,则只需要将数字序列转换成五进制得到路径,求出黑色结点表示的区域,将对应区域涂黑,最后输出即可。关于树的数据结构参考了之前trie树模板里树的结构,没有用指针,使用数组去模拟了指针。

  

#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
         #include 
        
          #include 
         
           using std::sort; using std::vector; using std::cin; using std::cout; using std::endl; const int NW = 1, NE = 2, SW = 3, SE = 4; const int WHITE = 0, BLACK = 1; const int NONE = -1; //自定义数据结构------------------------------------------------------- // 树的定义及操作 const int T_MAXSIZE = 20000000; // 树的容量 const int T_NEXTSIZE = 4; // 树每个结点有多少个子节点 int node[T_MAXSIZE]; // 结点 int next[T_MAXSIZE][T_NEXTSIZE]; // 子树 int size = 0; // 当前结点数量 inline void init_node() { size = 0; } // 初始化树 inline int newnode() { return size++; } // 创建新结点 // 图的定义及操作 int n; char G_t[100][100]; int G[100][100], sum[100][100]; inline void init_G() {} inline void calG() { for(int i = 1; i <= n; ++i) for(int j = n; j > 0; --j) G[i][j] = G_t[i][j - 1] - '0'; } inline void calsum() { for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) sum[i][j] = G[i][j] + sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1]; } bool same(const int &i1, const int &j1, const int &i2, const int &j2) { // 判断指定范围色块是否相同 int d = sum[i2][j2] - sum[i1-1][j2] - sum[i2][j1-1] + sum[i1-1][j1-1]; return d == 0 || d == (i2 - i1 + 1) * (j2 - j1 + 1); } // 数字序列的定义及操作 int S[10000], S_t[10000], S_size; vector 
           
           
             > S_5; inline void init_S() { S_size = 0; } inline void push_back(const int &d) { S[S_size++] = d; } // -------------------------------------------------------------------- inline void init(const bool &set0 = false) { // 初始化 init_node(), init_G(), init_S(); if(set0) { n *= -1; memset(G, 0, sizeof(G)); S_5.clear(); } } inline void build(const int &i1, const int &j1, const int &i2, const int &j2, const int &pt) { // 根据图建树 if(same(i1, j1, i2, j2)) node[pt] = G[i1][j1]; else { node[pt] = -1; int i_mid = (i1 + i2) / 2, j_mid = (j1 + j2) / 2; build(i1, j1, i_mid, j_mid, next[pt][0] = newnode()); build(i1, j_mid + 1, i_mid, j2, next[pt][1] = newnode()); build(i_mid + 1, j1, i2, j_mid, next[pt][2] = newnode()); build(i_mid + 1, j_mid + 1, i2, j2, next[pt][3] = newnode()); } } inline void dfs(const int &pt, const int &depth, const int &num) { // 根据树算出各个数字 S_t[depth] = num; if(node[pt] == BLACK) { int d = 0; for(int i = depth; i > 0; --i) d = d * 5 + S_t[i]; push_back(d); } else if(node[pt] == NONE){ dfs(next[pt][0], depth + 1, NW); dfs(next[pt][1], depth + 1, NE); dfs(next[pt][2], depth + 1, SW); dfs(next[pt][3], depth + 1, SE); } } inline void mode_G() { init(); for(int i = 1; i <= n; ++i) scanf("%s", G_t[i]); calG(), calsum(); build(1, 1, n, n, newnode()); dfs(0, 0, 0); sort(S, S + S_size); if(S_size) { bool first = true; for(int i = 0; i < S_size; ++i) { if(!(i % 12) && i != 0) { printf("\n"); first = true; } if(first) first = false; else printf(" "); printf("%d", S[i]); } printf("\n"); } printf("Total number of black nodes = %d\n", S_size); } inline void paint(const int &i1, const int &j1, const int &i2, const int &j2) { // 将指定区域画成黑色 for(int i = i1; i <= i2; ++i) for(int j = j1; j <= j2; ++j) G[i][j] = 1; } inline void mode_S() { init(true); int d; while(~scanf("%d", &d) && d != -1) push_back(d); for(int i = 0; i != S_size; ++i) { S_5.push_back(vector 
            
              ()); while(S[i] > 0) { S_5[i].push_back(S[i] % 5); S[i] /= 5; } } sort(S_5.begin(), S_5.end()); for(int i = 0; i != S_size; ++i) { int i1 = 1, j1 = 1, i2 = n, j2 = n; for(int j = 0; j != S_5[i].size(); ++j) { int i_mid = (i1 + i2) / 2, j_mid = (j1 + j2) / 2; if(S_5[i][j] == 1) i2 = i_mid, j2 = j_mid; if(S_5[i][j] == 2) i2 = i_mid, j1 = j_mid + 1; if(S_5[i][j] == 3) i1 = i_mid + 1, j2 = j_mid; if(S_5[i][j] == 4) i1 = i_mid + 1, j1 = j_mid + 1; } paint(i1, j1, i2, j2); } for(int i = 1; i <= n; ++i) { for(int j = 1; j <= n; ++j) printf("%c", G[i][j] ? '*' : '.'); printf("\n"); } } int main() { int T = 0; while(~scanf("%d", &n) && n) { if(T) printf("\n"); printf("Image %d\n", ++T); if(n > 0) mode_G(); else mode_S(); } } 
             
            
           
          
         
       
      
      
     
     
    
    
   
   

  

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值