[DFS]Ancient Messages, World Finals 2011, Uva1103

本文介绍了一种识别特定象形文字的算法实现。该算法利用深度优先搜索(DFS)技术来区分不同象形文字间的白色区域数量,以此作为判断依据。通过对输入图像进行预处理并应用两次DFS遍历,实现了准确识别并输出符号。

题意:识别六种象形文字。输入的图像为一个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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值