【问题标题】:How to match ASCII art segments within ASCII art?如何匹配 ASCII 艺术中的 ASCII 艺术片段?
【发布时间】:2013-06-27 12:15:44
【问题描述】:

我正在为一个编程竞赛练习,在这个竞赛中我可以选择使用 Python 还是 C++ 来解决每个问题,因此我愿意接受任何一种语言的解决方案——无论哪种语言最适合这个问题。

我遇到的上一个问题的 URL 是 http://progconz.elena.aut.ac.nz/attachments/article/74/10%20points%20Problem%20Set%202012.pdf,问题 F(“地图”)。

基本上,它涉及在一个大的 ASCII 艺术中匹配出现的一小块 ASCII 艺术。在 C++ 中,我可以为每幅 ASCII 艺术作品制作一个矢量。问题是小块多行时如何匹配。

我不知道该怎么做。我不想要为我编写的所有代码,只想了解问题所需的逻辑。

感谢您的帮助。

这是我目前所得到的:

#include <cstdlib>
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>

using namespace std;

int main( int argc, char** argv )
{
    int nScenarios, areaWidth, areaHeight, patternWidth, patternHeight;

    cin >> nScenarios;

    for( int a = 0; a < nScenarios; a++ )
    {
        //get the pattern info and make a vector
        cin >> patternHeight >> patternWidth;
        vector< vector< bool > > patternIsBuilding( patternHeight, vector<bool>( patternWidth, false ) );

        //populate data
        for( int i = 0; i < patternHeight; i++ )
        {
            string temp;
            cin >> temp;
            for( int j = 0; j < patternWidth; j++ )
            {
                patternIsBuilding.at( i ).at( j ) = ( temp[ j ] == 'X' );
            }
        }

        //get the area info and make a vector
        cin >> areaHeight >> areaWidth;
        vector< vector< bool > > areaIsBuilding( areaHeight, vector<bool>( areaWidth, false ) );

        //populate data
        for( int i = 0; i < areaHeight; i++ )
        {
            string temp;
            cin >> temp;
            for( int j = 0; j < areaWidth; j++ )
            {
                areaIsBuilding.at( i ).at( j ) = ( temp[ j ] == 'X' );
            }
        }


        //now the vectors contain a `true` for a building and a `false` for snow
        //need to find the matches for patternIsBuilding inside areaIsBuilding
        //how?

    }


    return 0;
}

编辑:从下面的 cmets 中,我得到了来自 J.F. Sebastian 的 Python 解决方案。它有效,但我不明白这一切。我已经评论了我可以但需要帮助来理解 count_pattern 函数中的 return 语句。

#function to read a matrix from stdin
def read_matrix():

    #get the width and height for this matrix
    nrows, ncols = map( int, raw_input().split() )

    #get the matrix from input
    matrix = [ raw_input() for _ in xrange( nrows ) ]

    #make sure that it all matches up
    assert all(len(row) == ncols for row in matrix)

    #return the matrix
    return matrix

#perform the check, given the pattern and area map
def count_pattern( pattern, area ):

    #get the number of rows, and the number of columns in the first row (cause it's the same for all of them)
    nrows = len( pattern )
    ncols = len( pattern[0] )

    #how does this work?
    return sum(
        pattern == [ row[ j:j + ncols ] for row in area[ i:i + nrows ] ]
        for i in xrange( len( area ) - nrows + 1 )
        for j in xrange( len( area[i] ) - ncols + 1 )
    )

#get a number of scenarios, and that many times, operate on the two inputted matrices, pattern and area
for _ in xrange( int( raw_input() ) ):
    print count_pattern( read_matrix(), read_matrix() )

【问题讨论】:

  • 作为一个起点,我建议您将大部分和小部分都定义为二维数组,可能是布尔值,其中true 表示建筑物,false 表示雪。然后,您需要使用一些循环符来查找大矩阵中的每个出现的小矩阵。
  • @Vulcan 谢谢,这似乎可行。我会试一试的。也许将其添加为答案,以便我接受它:)
  • 我不满意我的评论作为答案(这就是为什么它是评论),但我可能会尝试编写一个实际的矩阵内矩阵定位算法。我对 C++ 或 Python 都不是很熟悉,所以这对我来说是一个很好的练习,但不要忘记你也可以随时用代码回答自己的问题!
  • 好的,谢谢。考虑到我得到的任何建议,我正忙于尝试处理它(目前在 C++ 中)
  • 这里是a brute-force implementation in Python。您可以使用它来测试您的各种输入的解决方案。

标签: c++ python ascii-art


【解决方案1】:
#include <iostream>
#include <vector>

using namespace std;

int main(){

    int numOfRounds;
    cin >> numOfRounds;



    for(int round = 0; round < numOfRounds; round++){

        int out = 0;

        int linesToMatch;
        cin >> linesToMatch;

        int sizeToMatch;
        cin >> sizeToMatch;

        vector <string> v;
        string t;

        for (int i = 0; i < linesToMatch; i++){
            cin >> t;
            v.push_back(t);
        }

        string s = "";

        int rows;
        cin >> rows;

        int columns;
        cin >> columns;

        for (int j = 0; j < rows; j++){        //map->string
            cin >> t;
            s += t;
        }

        // main part of implementation
        // it's mainly basic algebra and index tracking
        for (int m = 0; m <= rows - linesToMatch; m++){
            for (int n = 0; n <= columns - sizeToMatch; n++){
                int x;
                for (x = 0; x < linesToMatch; x++){
                    int index = (m + x) * columns + n;
                    string newTemp(s.begin() + index, s.begin() + index + sizeToMatch);
                    if (newTemp != v.at(x)) break;
                }
                if (x == linesToMatch) out++;
            }
        }

        cout << out << endl;

    }

}

【讨论】:

  • 对不起,我不是那个意思。如果您向下滚动,您会遇到问题 F(标题为“地图”)。
  • 谢谢。是的,这对我来说是一样的,我可以做到,但我不知道如何处理多行模式。
【解决方案2】:
#how does this work?
return sum(
    pattern == [ row[ j:j + ncols ] for row in area[ i:i + nrows ] ]
    for i in xrange( len( area ) - nrows + 1 )
    for j in xrange( len( area[i] ) - ncols + 1 )
)

生成器表达式可以使用显式的 for 循环块重写:

count = 0
for i in xrange( len( area ) - nrows + 1 ):
    for j in xrange( len( area[i] ) - ncols + 1 ):
        count += (pattern == [ row[ j:j + ncols ]
                              for row in area[ i:i + nrows ] ])
return count

比较 (pattern == ..) 返回 True/False,在 Python 中等于 1/0。

构建子矩阵以与模式进行比较的列表推导可以优化为更早返回:

count += all(pattern_row == row[j:j + ncols]
             for pattern_row, row in zip(pattern, area[i:i + nrows]))

或者使用显式的for循环块:

for pattern_row, row in zip(pattern, area[i:i + nrows]):
    if pattern_row != row[j:j + ncols]:
       break # no match (the count stays the same)
else: # matched (no break)
    count += 1 # all rows are equal

【讨论】:

    【解决方案3】:

    不要用线条来思考。将整个页面读入一个字符串,并像对待任何其他字符一样处理行尾字符。

    (您可能认为这是一个神秘的提示,但您确实只是要求“一个想法”如何做到这一点。)

    编辑:由于您知道图片的整体尺寸,因此您可以从您尝试匹配的模式的第一行向前计数字符以匹配第二行,以此类推以匹配后续行。

    【讨论】:

    • 好的。这是一个很好的观点,但看看我链接到的问题中的例子,我看不出它是如何工作的。换行符确实很重要。抱歉,我无法真正解释,但看看这个例子你可能会明白。
    • 通过忽略 EOL,输入失去了所有二维意义,这意味着它无法匹配到类似矩阵的输入。如果您建议将 EOL 替换为另一个字符并将整个输入视为向量,这基本上就是它已经做的事情,但 EOL 在以类似矩阵的格式显示二维信息方面提供了最清晰的效果。
    猜你喜欢
    • 2016-10-12
    • 2010-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-02
    • 1970-01-01
    相关资源
    最近更新 更多