Ancient Messages UVA - 1103

Posted caijiaming

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ancient Messages UVA - 1103相关的知识,希望对你有一定的参考价值。

题目链接:https://vjudge.net/problem/UVA-1103

技术图片

技术图片

技术图片

技术图片

 

 题目大意:每组数据包含H行W列的字符矩阵(H<=200,W<=50) 每个字符为为16进制  你需要把它转化为二进制。  转化为二进制之后 1代表黑点 0代表白点

问你出现的所有符号  并按字典序输出!

思路:首先看到这道题,完全没看懂题意 ,真的没看懂,后来搜了题解才看明白题意,但是还是不会做,这道题是在紫书上看到的,紫书上并没有给出代码,学了别人的博客!

好了  具体怎么做呢? 

仔细观察可以发现,每个字符中出现的圆是不一样的,看一道题,很多时候就是找特征量,用特征量来区分题目中的量! 这题的特征量就是每个字符中圆的个数了!  读者仔细看一下图就能明白了

然后我们知道了特征量是圆 所以我们求得该图形有多少个圆是不是就知道了是哪个图形呢?  当然是的

但是问题来了,怎么求得图形内有多少个圆呢?  我也想了很久 ,这个到底怎么控制,首先你得知道那些白点是不是构成圆,而且这些圆还要在黑色像素之内。  感觉完全没有思路呀 

注意题目中说了,两个图形并不会相接触,这就很重要了,不会相接触,那么我们想一下,当我们知道了一条黑色曲线,是不是与它相接触的白点就是圆环?  有人可能会说,不一定吧  也可能不构成圆环啊

是的 ,的确有可能,不构成圆环的话肯定是最外围的那一些白色点,我们把这些点连成一个连通块,考虑情况的时候把它忽略就行了。   所以要解决这道题的关键就是分析上面内容了

其他的就是求连通块,注意黑色连通块要存起来,因为我们是通过黑色连通块来寻找有多少个白色圆环的   到这这道题就解决了

看代码:

#include<iostream>
#include<vector>
#include<set>
#include<string.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxh=200+5;
const int maxw=50*4+5;
char bin[256][5];
int H,W,pic[maxh][maxw],color[maxh][maxw];
char line[maxw];
//pic[i][j]  i j 从1开始
void decode(char ch,int row,int col)
{
    for(int i=0;i<4;i++)
    {
        pic[row][col+i]=bin[ch][i]-0;
    }
}
const int dr[]={-1,1,0,0};
const int dc[]={0,0,-1,1};
void dfs(int row,int col,int c)//把属于一个连通块的归为一个color值
{
    color[row][col]=c;//该位置标记为访问过
    for(int i=0;i<4;i++)
    {
        int row2=row+dr[i];
        int col2=col+dc[i];
        //是否为合法的位置
        if(row2>=0&&row2<H&&col2>=0&&col2<W&&pic[row2][col2]==pic[row][col]&&color[row2][col2]==0)//是否为相等的元素
        {
            dfs(row2,col2,c);
        }
    }
}

vector<set<int> >neighbors;

//这里set集合的确用的好  这样就不会有重复的白色块了 !!!
void check_neighbors(int row,int col)
{
    for(int i=0;i<4;i++)
    {
        int row2=row+dr[i];
        int col2=col+dc[i];//color 为1 代表是最外围的白色部分  并不是圈
        if(row2>=0&&row2<H&&col2>=0&&col2<W&& pic[row2][col2]==0&&color[row2][col2]!=1)
            neighbors[color[row][col]].insert(color[row2][col2]);
    }
}

/*

Ankh: A   1个
Wedjat: J 3个
Djed: D   5个
Scarab: S 4个
Was: W    0个
Akhet: K  2个

*/

const char* code="WAKJSD";//以有多少个圈来排序   刚好是012345个
//以容器长度来表示黑连通块旁的内白连通块数
char recognize(int c)
{
    int cnt=neighbors[c].size();//该黑色连通块有周围有多少个白圈
    return code[cnt];
}

int main()
{
    strcpy(bin[0],"0000");//这里相当于bin[i]  i是字符1的ascii码
    strcpy(bin[1],"0001");
    strcpy(bin[2],"0010");
    strcpy(bin[3],"0011");
    strcpy(bin[4],"0100");
    strcpy(bin[5],"0101");
    strcpy(bin[6],"0110");
    strcpy(bin[7],"0111");
    strcpy(bin[8],"1000");
    strcpy(bin[9],"1001");
    strcpy(bin[a],"1010");
    strcpy(bin[b],"1011");
    strcpy(bin[c],"1100");
    strcpy(bin[d],"1101");
    strcpy(bin[e],"1110");
    strcpy(bin[f],"1111");
    int ca=0;
    while(cin>>H>>W)
    {
        if(H==0&&W==0) break;
        memset(pic,0,sizeof(pic));
        for(int i=0;i<H;i++)
        {
            scanf("%s",line);
            for(int j=0;j<W;j++)
            {
                decode(line[j],i+1,j*4+1);//转换为对应的二进制
            }
        }
        H+=2;//这两步是为何  为何要加2???难道是把原来的包围起来???
        W=W*4+2;//是的  如果不这样的话 不能保证最外围的白色一定是1

        int cnt=0;//存有多少个连通块
        vector<int> cc;//存所有黑色连通块
        memset(color,0,sizeof(color));//标记数组
        for(int i=0;i<H;i++)
        {
            for(int j=0;j<W;j++)
            {
                if(!color[i][j])//没有标记过
                {
                    dfs(i,j,++cnt);
                    if(pic[i][j]==1) cc.push_back(cnt);//扫描矩阵 且为所有连通块编号  并把黑连通块存进cc容器中


                }
            }
        }
        neighbors.clear();
        neighbors.resize(cnt+1);//设置容器大小  原来这步是不能少的  !!  少了的话 neighbors[i]  就出错了!!  切记!!
        for(int i=0;i<H;i++)//再扫描一遍??
        {
            for(int j=0;j<W;j++)
            {
                if(pic[i][j]==1)
                    check_neighbors(i,j);//扫描黑点 并把该点旁边有几个内连通白块存入neighbors容器  其实下标为黑点对应的连通块编号
            }
        }
        vector<char>ans;
        for(int i=0;i<cc.size();i++)//遍历所有的黑色连通块
            ans.push_back(recognize(cc[i]));//存目标值 并排序
        sort(ans.begin(),ans.end());

        printf("Case %d: ",++ca);
        for(int i=0;i<ans.size();i++) printf("%c",ans[i]);
        printf("
");
    }
    return 0;
}

 

以上是关于Ancient Messages UVA - 1103的主要内容,如果未能解决你的问题,请参考以下文章

UVA1103 Ancient Messages 题解

UVa 1339 - Ancient Cipher

UVA 1586Ancient Cipher

UVa 1339 Ancient Cipher --- 水题

UVa 1339 Ancient Cipher

Uva 1339:Ancient Cipher