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("\n");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/caijiaming/p/10353619.html

时间: 2024-10-08 15:12:08

Ancient Messages UVA - 1103的相关文章

K - Ancient Messages(dfs求联通块)

K - Ancient Messages Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice UVA 1103 Appoint description: Description In order to understand early civilizations, archaeologists often study texts written in ancie

图-用DFS求连通块 UVa 1103

这道题目甚长, 代码也是甚长, 但是思路却不是太难.然而有好多代码实现的细节, 确是十分的巧妙. 对代码阅读能力, 代码理解能力, 代码实现能力, 代码实现技巧, DFS方法都大有裨益, 敬请有兴趣者耐心细读.(也许由于博主太弱, 才有此等感觉). 题目: UVa 1103 In order to understand early civilizations, archaeologists often study texts written in  ancient languages. One

uva 1103

#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <cstdlib> #include <stack> #include <cctype> #include <string> #include <malloc.h> #include

UVA 1103 Ancient Messages (DFS)

起初学习dfs的时候 看不懂这个题目  回过头来今天看的时候思路相对比较清晰了.但还是想不到怎么处理 查询有多少个空白洞.并且一个图中还有好多个象形字符.网上思路是 在周围扩展一圈0,使得文字之外的所有0 都连通,一次dfs标记所有文字之外的0为-1.然后遍历图,发现1就沿着有1 的路径dfs2,在这个过程中,如果发现0,那么必然是文字内部的空洞,此时把空洞dfs 置为-1,标记以后不再走.那么发现几次0就有几个空洞在文字中.那么每一次的dfs2,就处理了一个象形文字.cnt的值就是空洞的个数即

UVa 1103 (利用连通块来判断字符) Ancient Messages

本题就是灵活运用DFS来求连通块来求解的. 题意: 给出一幅黑白图像,每行相邻的四个点压缩成一个十六进制的字符.然后还有题中图示的6中古老的字符,按字母表顺序输出这些字符的标号. 分析: 首先图像是被压缩过的,所以我们要把它解码成一个01矩阵.而且我们还要在原图像的四周加一圈白边,这样图中的白色背景都连通起来了. 黑色连通块的个数就是字符的个数. 观察题中字符样式可知,每种字符中包裹的“白洞”的个数是不同的,所以我们可以根据每个字符中的“白洞”的个数来区别这些字符. 然后我们给所有的连通块染色,

uva 1103 - Ancient Messages(象!形!文!字! dfs遍历计数)

我今天做的这叫什么题-- 今天这个题直接跪了,一看十六进制直接懵了.. 然后在csdn上竟然发现了身边直系学长写的解题报告,然后问了一下解题的思路.然后写出来的代码,想要测试数据吗吧哈哈 给一组最基本的~ 5 3 fff f0f fff f0f fff 输出应该是K AC代码如下: #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace

Ancient Message (古埃及象形文字识别 Uva 1103)

原题:https://uva.onlinejudge.org/external/11/1103.pdf 给一幅图(16进制), 判断图中有哪些象形文字. 只识别 这6个就可以 示例: 将16进制数据 转换为 二进制数据 然后输出象形文字的名字 原理: 其实很简单,因为这六个象形文字比较特殊,每个文字包含的空心部分个数不一样. 比如Ankh有一个空心部分,Wedjat有3个空心部分.所以只要先用dfs找到象形文字,然后数一数 每个有几个空心部分就可以了. 1 #include <cstdio>

Uva1103 Ancient Messages

题意:识别图中的象形文字.但是,图形可以任意的拉伸,但不能拉断. 分析:这种题如果图形没有特征是不可做类型的题,不过观察图形可以发现每个图形中的洞的数量是一定的,我们只需要数出每一个封闭图形的洞数就能知道这是哪个图形. 虽然知道了原理,但是并不是特别好做,首先我们需要一次dfs将所有图形旁边的点全都变为"不可访问",然后从每个黑点开始枚举,向四周扩展,遇到白色的块就用第一次的dfs函数覆盖,否则继续第二次dfs,两次dfs交错使用,思路比较巧妙. #include <cstdio

Uva 1103 古代象形符号(dfs求连通块, floodfill, 进制转换)

题意: 给定一个H行W列的字符矩阵(H<200, W < 50), 输入的是一个十六进制字符, 代表一行四个相邻的二进制, 1代表像素, 0代表没有像素. 然后要求判断输入的是以下哪些图形,注意图形可以伸缩变换, 但不能拉断. 分析: 因为图形可以伸缩变换, 所以只要关注每个图形的特征, 题目表中的6个符号从左到右依次有1,3,5,4,0,2个白洞 我们先把十六进制还原成二进制建一幅图, 然后上下各留空一行, 左右各留空一列, 先把最外面的白色floodfill了(增加两行两列后保证外面的白色