Classic example of introduction to algorithm competition 6-13

Keywords: Algorithm

UVa1103

Ancient Messages

Identify hieroglyphs.

Because there is only one black connected pixel block in a hieroglyphic, and the hieroglyphics do not cover each other, the hieroglyphics can be divided according to the black connected pixel block; Because the number of white connected pixel blocks in each hieroglyphic is different, the hieroglyphic can be identified according to the number of white connected pixel blocks. Therefore, the problem is transformed into the problem of identifying black-and-white connected pixel blocks, which can be solved by DFS.

This question was submitted 22 times before it was completely AC, but even so, I still don't know where the error is, so I can only submit it according to the problem solution. In order to reduce the size of the hieroglyphic picture as much as possible in the process of counting the white connected pixel blocks, the code records the upper, lower, left and right boundaries of the hieroglyphic currently to be recognized in the process of traversing the black connected pixel blocks, then copies the obtained rectangle to a new picture, and adds a circle of white pixels around as the outer boundary.

The difference between right and wrong is the code for copying hieroglyphic pictures (69 ~ 72 lines). If only line 70 is reserved, that is, the rectangular hieroglyphic is copied directly, and then the number of white connected pixel blocks is counted, WA is after submission (but it can pass the uDebug test case), but only the black pixels in this hieroglyphic are copied, and AC is after submission. The difference between the two is that the rectangular hieroglyphs may contain black connected pixel blocks that are part of other hieroglyphs. It seems that it should not affect the statistics of the number of white connected pixel blocks, but there is no counterexample.

Finally, many codes on the Internet are DFS in 8 directions, but in fact, the title means 4.

#include <iostream>
#include <algorithm>
#include <bitset>
#include <map>
#include <string>
#include <vector>

using namespace std;

class Solution
{
public:
	Solution(size_t H, size_t W, istream &is)
		: image(vector<string>(H)), ImageVisitingState(vector<vector<PixelState>>(H, vector<PixelState>(4 * W, PixelState::UNVISITED)))
	{
		for (size_t i = 0; i < H; i++)
		{
			string line;
			is >> line;
			for (char ch : line)
			{
				bitset<4> hex(stoi(string(1, ch), NULL, 16));
				image[i].append(hex.to_string());
			}
		}
		for (size_t i = 0; i < H; i++)
		{
			for (size_t j = 0; j < image[i].length(); j++)
			{
				if (image[i][j] == '1' && ImageVisitingState[i][j] == PixelState::UNVISITED) {
					size_t left = j, right = j, top = i, bottom = i;
					GetCharacterBoundary(i, j, left, right, top, bottom);
					char ch = RecognizeCharacter(left, right, top, bottom);
					CharacterFrequency[ch]++;
				}
			}
		}
	}
	map<char, int> CharacterFrequency;
private:
	enum class PixelState
	{
		UNVISITED, VISITING, VISITED
	};
	vector<string> image, duplicate;
	vector<vector<PixelState>> ImageVisitingState, DupVisitingState;
	static array<string, 16> binary;
	static vector<char> WhiteHole2Character;
	void GetCharacterBoundary(size_t i, size_t j, size_t &left, size_t &right, size_t &top, size_t &bottom)
	{
		if (image[i][j] != '1' || ImageVisitingState[i][j] != PixelState::UNVISITED) return;
		ImageVisitingState[i][j] = PixelState::VISITING;
		left = min(j, left), right = max(j, right);
		top = min(i, top), bottom = max(i, bottom);
		if (i > 0) GetCharacterBoundary(i - 1, j, left, right, top, bottom);
		if (j > 0) GetCharacterBoundary(i, j - 1, left, right, top, bottom);
		if (j + 1 < image[i].length()) GetCharacterBoundary(i, j + 1, left, right, top, bottom);
		if (i + 1 < image.size()) GetCharacterBoundary(i + 1, j, left, right, top, bottom);
	}
	char RecognizeCharacter(size_t left, size_t right, size_t top, size_t bottom)
	{
		size_t row = bottom - top + 3, col = right - left + 3;
		duplicate.assign(row, string(col, '0'));
		DupVisitingState.assign(row, vector<PixelState>(col, PixelState::UNVISITED));
		for (size_t i = top; i <= bottom; i++)
		{
			for (size_t j = left; j <= right; j++)
			{
				if (ImageVisitingState[i][j] == PixelState::VISITING) {
					duplicate[i - top + 1][j - left + 1] = image[i][j];
					ImageVisitingState[i][j] = PixelState::VISITED;
				}
			}
		}

		int WhiteHole = 0;
		for (size_t i = 0; i < duplicate.size(); i++)
		{
			for (size_t j = 0; j < duplicate[i].length(); j++)
			{
				if (duplicate[i][j] == '0' && DupVisitingState[i][j] == PixelState::UNVISITED) {
					CountWhiteHole(i, j);
					WhiteHole++;
				}
			}
		}
		return WhiteHole2Character[WhiteHole - 1];
	}
	void CountWhiteHole(size_t i, size_t j)
	{
		if (duplicate[i][j] != '0' || DupVisitingState[i][j] == PixelState::VISITED) return;
		DupVisitingState[i][j] = PixelState::VISITED;
		if (i > 0) CountWhiteHole(i - 1, j);
		if (j > 0) CountWhiteHole(i, j - 1);
		if (j + 1 < duplicate[i].length()) CountWhiteHole(i, j + 1);
		if (i + 1 < duplicate.size()) CountWhiteHole(i + 1, j);
	}
};

vector<char> Solution::WhiteHole2Character = { 'W', 'A', 'K', 'J', 'S', 'D' };

ostream& operator<<(ostream &os, const Solution &solution)
{
	for (auto p : solution.CharacterFrequency)
	{
		os << string(p.second, p.first);
	}
	return os;
}

int main()
{
	int cases = 0;
	size_t H, W;
	while (cin >> H >> W) {
		if (H == 0 && W == 0) break;
		Solution solution(H, W, cin);
		cout << "Case " << ++cases << ": " << solution << endl;
	}
	return 0;
}
/*

*/

Posted by tskweb on Thu, 07 Oct 2021 17:24:24 -0700