Gym102770 C - Crossword Validation

题目链接: Problem - C - Codeforces

Problem Description

        A crossword is a word puzzle that usually takes the form of a square or a rectangular grid of white- and black-shaded cells. The game's goal is to fill the white cells with letters, forming words or phrases, by solving clues, which lead to the answers. The answer words and phrases are typically placed in the grid from left to right and from top to bottom. The shaded cells are used to separate the words or phrases. Crossword grids such as those appearing in most North American newspapers and magazines feature solid areas of white cells. Every letter is checked (i.e. is part of both an "across" word and a "down" word) and usually each answer must contain at least three letters. In such puzzles, shaded cells are typically limited to about one-sixth of the total. Crossword grids elsewhere, such as in Britain, South Africa, India and Australia, have a lattice-like structure, with a higher percentage of shaded cells, leaving about half the letters in an answer unchecked. For example, if the top row has an answer running all the way across, there will often be no across answers in the second row.

        Crossword puzzles have a long history. The title for the world's first crossword puzzle is disputed, but most people believe the crossword puzzle is invented in the 19th century. With the emergence of personal computers, more and more crossword puzzles are distributed online instead of on newspapers and books. Software that aids in creating and solving crossword puzzles has been written since at least 1976. In this problem, you are to write a program that checks if a solution for a crossword puzzle is valid. Note that the rules of the puzzle in this problem, which is described in the next paragraph, may differ from the real-world ones.

        You are given a completed crossword puzzle on a N×N grid. Each cell is either a white cell filled with a letter or a black cell. You are also given a dictionary of M distinct words, where each word has a score associated with it. A horizontal candidate word in the grid is a continuous string of letters on the same row of the grid that can't be extended. Formally, this means that the cell to the left of the leftmost cell of the candidate word either doesn't exist or is a black cell, and the same goes for the cell to the right of the rightmost cell. Vertical candidate words are defined similarly, except that the letters are on the same column. Candidate words are read from left to right for horizontal words or from top to bottom for vertical words. The crossword puzzle is valid if and only if each candidate word is present in the given dictionary. The score of a valid puzzle is the sum of the scores in the dictionary associated with each candidate word. Note that two or more candidate words may be the same. In this case, the score of that word is added multiple times accordingly. Your program must determine the score of the solution, or report that it is not valid.

题目翻译:

        填字游戏是一种字谜游戏,通常采用正方形或矩形网格的形式,网格由白色和黑色阴影组成。游戏的目标是用字母填充白色细胞,通过解决线索形成单词或短语,从而找到答案。答案单词和短语通常从左到右,从上到下放置在网格中。阴影的单元格用来分隔单词或短语。在大多数北美报纸和杂志上出现的纵横字谜网格都以白色细胞的固体区域为特征。每个字母都要被检查(即是“across”单词和“down”单词的一部分),通常每个答案必须包含至少三个字母。在这样的谜题中,阴影细胞通常被限制在总数的六分之一左右。在其他地方,如英国、南非、印度和澳大利亚,填字游戏的格子结构类似于格子,其中阴影格子的比例更高,因此答案中大约有一半的字母没有被选中。例如,如果第一行的答案是横贯的,那么在第二行中通常不会有横贯的答案。

        填字游戏有着悠久的历史。世界上第一个填字游戏的头衔是有争议的,但大多数人认为填字游戏是在19世纪发明的。随着个人电脑的出现,越来越多的填字游戏在网上分发,而不是在报纸和书本上。至少从1976年起,人们就开始编写用于创建和解决填字游戏的软件。在这个问题中,你要写一个程序来检查一个填字游戏的答案是否有效。请注意,这个问题中的谜题规则(将在下一段中描述)可能与现实世界中的规则不同。

        你将在N×N网格上完成一个填字游戏。每个细胞要么是充满字母的白色细胞,要么是黑色细胞。您还会得到一个包含M个不同单词的字典,其中每个单词都有一个与之相关的分数。网格中的水平候选词是网格同一行上的连续字母串,不能扩展。形式上,这意味着候选单词最左边单元格的左边单元格要么不存在,要么是一个黑色单元格,最右边单元格的右边单元格也是如此。垂直候选词的定义类似,只是字母在同一列上。水平单词从左到右读,垂直单词从上到下读。当且仅当每个候选单词存在于给定字典中时,填字游戏有效。有效谜题的分数是与每个候选单词相关的字典中分数的总和。注意,两个或更多的候选词可能是相同的。在这种情况下,该单词的分数会相应增加多次。您的程序必须确定该解决方案的分数,否则报告该解决方案无效。

Input

        The input contains multiple cases. The first line of the input contains a single positive integer T, the number of cases.For each case, the first line of the input contains two integers N,M (1 ≤ N ≤ 1000, 1 ≤ M ≤ 4×1e6),the size of the grid and the number of words in the dictionary. The following N lines each contain a string of length N, where each character is either a lowercase English letter or '#'. If the j-th character of the i-th string is '#', then the cell located in the intersection of the i-th row and the j-th column is a black cell. Otherwise, this character denotes the letter filled in that cell. The following M lines each contain a non-empty string consisting of only lowercase English letters, and a positive integer, denoting a word in the dictionary and its score. It is guaranteed that those M words are pairwise distinct, the length of each word doesn't exceed N, and the score of each word doesn't exceed 1e9.

        It is guaranteed that the sum of N^2 over all cases doesn't exceed 4×1e6, and the sum of the lengths of all words in the dictionary over all cases doesn't exceed 4×1e6.

Input翻译:

        输入包含多组测试数据。输入的第一行包含一个正整数T,即组数。对于每种情况,输入的第一行包含两个整数N,M(1 ≤ N ≤ 1000,1 ≤ M ≤ 4e6),网格的大小和字典中的单词数。

        下面的N行每行包含一个长度为N的字符串,其中每个字符要么是小写英文字母,要么是 '#'。如果第i个字符串的第j个字符为 '#',则位于第i行和第j列交点的单元格为黑色单元格。否则,此字符表示填充在该单元格中的字母。

        下面的M行每行包含一个仅由小写英文字母组成的非空字符串和一个正整数,表示字典中的单词及其分数。保证这 M 个单词是两两不同的,每个单词的长度不超过 N,每个单词的得分不超过10^9。

        可以保证 N^2 在所有情况下的和不超过 4e6,并且字典中所有单词的长度在所有情况下的和不超过 4e6。

Output

For each case, print a single integer in a single line, the score of the crossword solution given in the input if it is valid. If the solution is not valid, print −1 instead.

Sample Input

2
2 4
ab
#d
ab 1
a 2
d 3
bd 4
2 4
ab
c#
ab 5
ca 2
b 6
c 7

Sample Output

10
-1

 

解题思路

题目大意:给定一个N*N的网格和M个不同单词的字典,网格中的单词只能从上往下读或者从左往右读,遇到 '#' 时断开,且单词必须取最长(如 “#abcde#fgh” 不能只取 abc),当网格中的所有单词都在字典里可以查到时,网格有效,输出单词的分数总和,否则输出 -1。

这里可以用字典树把字典里的每个词都存起来,然后把网格里的单词一个个分出来查询是否存在于字典树里,查不到输出 -1。但是我刚刚在写博客的时候突然想到用 unordered_map 存是不是也可以,unordered_map 是用哈希表实现的,插入和查询接近O(1),就去试了一下,发现真的可以,甚至还比字典树快一点点,是我想复杂了( ̄▽ ̄)"。下面是用哈希表实现的代码,字典树下次遇到再讲。

实现代码

#include <bits/stdc++.h>

using namespace std;

const int N = 1e3 + 5;
int n, m, x;
string a[N];
string s;

unordered_map<string, int> mp;

void solve() {
    // 每次初始化mp
    mp.clear();
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    for (int i = 0; i < m; i++) {
        cin >> s >> x;
        mp[s] = x;
    }

    // 这里注意要开long long
    long long res = 0;

    for (int i = 0; i < n; i++) {
        string ss, st;
        for (int j = 0; j < n; j++) {
            // 按行找
            if (a[i][j] != '#') {
                ss += a[i][j];
            } else {
                if (ss != "" && mp[ss] == 0) {
                    cout << -1 << endl;
                    return;
                } else {
                    res += mp[ss];
                    ss = "";
                }
            }

            // 按列找
            if (a[j][i] != '#') {
                st += a[j][i];
            } else {
                if (st != "" && mp[st] == 0) {
                    cout << -1 << endl;
                    return;
                } else {
                    res += mp[st];
                    st = "";
                }
            }
        }

        // 处理最后不是#结尾的情况
        if (ss != "") {
            if (mp[ss]) {
                res += mp[ss];
            } else {
                cout << -1 << endl;
                return;
            }
        }
        
        if (st != "") {
            if (mp[st]) {
                res += mp[st];
            } else {
                cout << -1 << endl;
                return;
            }
        }
    }
    // 前面没有return,说明全找到了,输出结果
    cout << res << endl;
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
}

运行结果

f5e4bc9d85844016b1ba9f614e8615e3.png

哈希表比字典树节约了很多空间

 

  • 27
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值