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
*/




posted @ 2017-10-31 11:14  mofushaohua  阅读(163)  评论(0编辑  收藏  举报