题意:识别六种象形文字。输入的图像为一个n*m的字符矩阵,每一个字符都为4个相邻像素的16进制表示(例如10011100对应9c)。转化为二进制后1代表黑点,0代表白点。输入的图像中有且仅有给定的六种文字,且一定和给定的文字拓扑等价(可以随意拉伸但不能拉断),并且不同的符号不会互相接触或包含。要求按照字典序输出所有的符号。
woc我感觉这个脑洞我是开不出来的23333
题解:所有的符号仅能保证拓扑等价,也就是说需要用一个拉伸无法改变的量来判断符号。通过观察六种符号可以发现每种符号所拥有的白色区域数目各不相同,因此可以通过符号中白色区域的数目来判断符号种类。
基本思路是两个DFS,为了方便遍历将得到的矩阵外面加一圈0以防出现符号边界在矩阵边界上的情况。首先将外面一圈不属于任何符号的白点标记,然后遍历一遍矩阵,每当碰到黑点时即为出现了一个符号,从这个黑点开始第二次DFS,黑点标记,未标记的白点再深搜联通块。由于保证符号不相互接触,所以这时DFS到的一定是属于同一个符号的点,并且通过标记黑点使得一个符号只被搜索一次。遍历完整个矩阵后将所得的符号按字典序输出即可。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<stack>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 205
#define INF 0x3f3f3f3f
#define eps 1e-8
const int mod=1e9+7;
using namespace std;
typedef long long ll;
int maze[maxn][maxn];
char cur[maxn][maxn];
int dis[8][2]={1,0,0,1,-1,0,0,-1};
char ancient[10]={'W','A','K','J','S','D'};
char ans[maxn*maxn];
int n,m,sum,cnt;
bool judge(int x,int y)
{
if(x>=0&&y>=0&&x<n&&y<m)
return true;
return false;
}
bool cmp(char a,char b){return a<b;}
void dfs(int x,int y)
{
if(!judge(x,y)||maze[x][y]!=0)
return;
maze[x][y]=-1;
for(int i=0;i<4;i++)
dfs(x+dis[i][0],y+dis[i][1]);
}
void dfs2(int x,int y)
{
if(!judge(x,y)||maze[x][y]==-1)
return;
if(maze[x][y]==0)
{
cnt++;
dfs(x,y);
return;
}
maze[x][y]=-1;
for(int i=0;i<4;i++)
dfs2(x+dis[i][0],y+dis[i][1]);
}
int main()
{
int kase=0;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)break;
memset(maze,0,sizeof(maze));
for(int i=0;i<n;i++)
{
scanf("%s",cur[i]);
for(int j=0;j<m;j++)
{
int num;
if(cur[i][j]>='a')num=cur[i][j]-'a'+10;
else num=cur[i][j]-'0';
for(int k=0;k<4;k++)
{
maze[i+1][j*4+4-k]=num%2;
num/=2;
}
}
}
m*=4,m+=2,n+=2;
dfs(0,0);
sum=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(maze[i][j]==1)
{
cnt=0;
dfs2(i,j);
ans[sum++]=ancient[cnt];
}
}
}
sort(ans,ans+sum,cmp);
printf("Case %d: ",++kase);
for(int i=0;i<sum;i++)
printf("%c",ans[i]);
printf("\n");
}
return 0;
}