CF1015E2 星星阵

1 CF1015E2 星星阵

2 题目描述

时间限制 \(3s\) | 空间限制 \(256M\)

星星的图形是由中心的星号字符 \(*\) 和相同长度的四条射线(左、右、上、下)构成。星星的大小是其射线的长度。星星的大小必须是正数(即长度不能为 \(0\))。空白位置用 \(.\) 表示。例如下面的图形:

最左边的图形是大小为 \(1\) 的星星,中间的图形是大小为 \(2\) 的星星,最右边的图形是大小为 \(3\) 的星星。给你一个 \(𝑛*𝑚\) 的只包含星号 \(*\) 和点 \(.\)的矩形。行的编号从 \(1\)\(𝑛\),列的编号从 \(1\)\(𝑚\)。如果可能的话使用任意数量的星星绘制这个网格。星星可以相互交叉、重叠甚至重合。输出的星星个数不能超过 \(𝑛*𝑚\)。每颗星都应该完全在网格内。可以使用相同大小和任意大小的星星。

3 题解

对于这道题,我们可以考虑一个时间复杂度略优于 \(O(n^3)\) 的算法:枚举所有 \(*\) 号,对于每个 \(*\) 号,我们枚举其上下左右同时延伸的情况下能延伸到的最远距离,并记录下这个星星和其覆盖的点。如果所有 \(*\) 号都被覆盖,说明星星可以覆盖所有的 \(*\) 号,否则不可以,输出 \(-1\)。由于这种算法中 \(*\) 号的个数可能到达 \(n^2\),而上下左右同时延伸的最坏情况约为 \(O(n)\),所以这个算法看上去是 \(O(n^3)\) 的,但事实真的如此吗?

我们发现:在边界时,我们枚举上下左右延伸的情况的那层循环实际上并不会跑满,而只会跑很小的一点。例如,在边界上只会跑 \(O(1)\) 的时间复杂度,就会因为不合法而退出。随着时间复杂度随着慢慢层数增加而增加,更深层的节点数慢慢减少。最终的时间复杂度略微高于 \(O(n^2)\),数量级大致在 \(10^7 - 10^8\)。由于这道题给了足足三秒,应该是可以跑过去的。

具体细节方面:我们可以利用一个 \(pair\) 队列将所有的 \(*\) 号存储起来,既方便查询元素又方便删除元素。存储答案时也类似,用 \(pair\) 队列存储当前星星的中心与向四周延伸的长度,最终输出答案时直接访问队头元素即可。用 \(bool\) 类型的数组存储每个点是否被覆盖,在输出前将所有的 \(*\) 号遍历一遍,如果有任意一个 \(*\) 号没有被覆盖到则直接输出 \(-1\)

4 代码(空格警告):

#include <iostream>
#include <queue>
#include <cstdio>
using namespace std;
const int N = 1005;
int n, m, x, y;
string s;
char Map[N][N];
bool fMap[N][N];
queue< pair<int, int> > q;
queue< pair< pair<int, int>, int> > ans;
bool check(int dx, int dy)
{
    if (dx < 1 || dx > n || dy < 1 || dy > m || Map[dx][dy] != '*') return 0;
    return 1;
}
int main()
{
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++)
    {
        cin >> s;
        for (int j = 1; j <= m; j++)
        {
            Map[i][j] = s[j-1];
            if (Map[i][j] == '*') q.push(make_pair(i, j));
        }
    }
    while (!q.empty())
    {
        x = q.front().first;
        y = q.front().second;
        q.pop();
        for (int i = 1; i <= n; i++)
        {
            if (i == 2) fMap[x][y] = 1;
            if (check(x-i, y) && check(x+i, y) && check(x, y+i) && check(x, y-i))
            {
                fMap[x-i][y] = 1;
                fMap[x+i][y] = 1;
                fMap[x][y+i] = 1;
                fMap[x][y-i] = 1;
            }
            else if (i != 1)
            {
                ans.push(make_pair(make_pair(x, y), i-1));
                break;
            }
            else break;
        }
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            if (Map[i][j] == '*' && fMap[i][j] == 0)
            {
                puts("-1");
                return 0;
            }
        }
    }
    printf("%lu\n", ans.size());
    while (!ans.empty())
    {
        printf("%d %d %d\n", ans.front().first.first, ans.front().first.second, ans.front().second);
        ans.pop();
    }
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-02-07 22:48  David24  阅读(105)  评论(0编辑  收藏  举报