题目大意:

给出两个整数n、m表示屏幕的长宽。屏幕上有一些窗口,每个窗口都是矩形的,窗口的边框用同一个大写字母来表示,不同的窗口的大写字母必定不同。

由于窗口的重叠,有些窗口的有些部分被其他窗口覆盖。但是,肯定有一些窗口在最顶端,不被其他任何窗口覆盖。我们称这些窗口为“顶端窗口”。你的任务就是找出所有的顶端窗口。

思路:

2008年北京赛区通过数最高的题目,一道简单的模拟题。只要注意一个窗口完全包含另一个窗口这种情况就好。

代码:

#include<iostream>
#include<stdio.h>
using namespace std;
char map[100][100];
int n,m;
struct point
//用结构体封装每个字母所表示窗口的信息。 
{
	int total;
	//字母出现的次数。 
	int max_x,min_x;
	//字母出现在图中的横坐标的最大值与最小值。 
	int max_y,min_y;
	//字母出现在图中的纵坐标的最大值与最小值。
	bool visit;
	//该字母是否出现过。 
	bool check_edge()
	//判断该字母所表示的窗口的边是否符合顶端窗口要求。 
	{
		if(total!=(max_x-min_x+max_y-min_y)*2)
		//根据字母数量判断窗口是否封闭。 
			return false;
		if(max_x-min_x<2||max_y-min_y<2)
		//判断窗口长宽是否满足>=3的要求。 
			return false;
		//若都满足,返回true。 
		return true;
	}
}letter[26];
void init()
//初始化。 
{
	for(int i=0;i<26;i++)
	{
		letter[i].total=0;
		letter[i].max_x=letter[i].max_y=0;
		letter[i].min_x=letter[i].min_y=100;
		letter[i].visit=false;
	}
}
bool cover(int i,int j)
//判断字母'A'+i所表示的窗口是否在字母'A'+j所表示窗口的内部。 
{
	if(letter[i].max_x<letter[j].max_x)
		if(letter[i].min_x>letter[j].min_x)
			if(letter[i].max_y<letter[j].max_y)
				if(letter[i].min_y>letter[j].min_y)
					return true;
	return false;
}
bool check(int x)
//判断字母'A'+x所表示的窗口是否为顶端窗口。 
{
	if(!letter[x].visit||!letter[x].check_edge())
	//若该字母没被访问过,或其所表示窗口的边不符合要求。 
		return false;
	for(int i=0;i<26;i++)
		if(i!=x&&letter[i].visit&&cover(i,x))
		//若有其它窗口在字母'A'+x所表示的窗口的内部。 
			return false;
	return true;
}
int main()
{
	while(scanf("%d%d",&n,&m)&&(n||m))
	{
		init();
		for(int i=0;i<n;i++)
			for(int j=0;j<m;j++)
			{
				scanf("\n%c",&map[i][j]);
				if(map[i][j]!='.')
				//若此处为字母,则更新该字母的信息。 
				{
					int x=map[i][j]-'A';
					letter[x].total++;
					letter[x].visit=true;
					if(letter[x].max_x<j)
						letter[x].max_x=j;
					if(letter[x].min_x>j)
						letter[x].min_x=j;
					if(letter[x].max_y<i)
						letter[x].max_y=i;
					if(letter[x].min_y>i)
						letter[x].min_y=i;
				}
			}
		for(int i=0;i<26;i++)
			if(check(i))
			//若字母'A'+i所表示的窗口为顶端窗口,则输出字母A+i。 
				printf("%c",'A'+i);
		printf("\n");
	}
}