(E2) Stars Drawing (Hard Edition)(dp,前缀和,覆盖)(搜索也可以)

本文介绍了如何解决一个二维矩阵中的星星排列问题,通过动态规划(dp)和前缀和(prefix sum)策略判断是否能将星星组成重叠的十字形状,并覆盖整个矩阵。利用judgex和judgey数组记录十字覆盖状态,通过两次扫描确定矩阵是否能完全被十字覆盖。若存在无法被覆盖的星星,则输出-1,否则输出十字中心坐标和边长。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意,给你一个n×m大小的字符矩阵,仅由‘.’和‘’组成,提问这个图可否划分为一些由‘’组成的十字形状,这些十字之间可以有重叠,如果可以完全覆盖输出每个十字中心坐标与边长度,不可以输出-1。

    这是一道很有意思的题,在这场比赛中上一道题是这一道题的简化版本,数据范围仅有100,所以我采用了O(n^3)的做法,即枚举每个 * ,然后向四周扩展,显然,在这道题中1000的数据范围中这种做法会超时。

   正确的做法类似与dp,首先开四个与字符数组相同大小的数组l,r,up,dn,然后进行两次扫描,这四个数组分别代表了从左边、右边、上边、下边开始数,数到当前位置的星号时已经有几个星号。然后再次扫描,枚举每一个星号,每一个星号上取l(i,j),

r(i,j),up(i,j),dn(i,j)中的最小值min(i,j),代表已当前位置为中心可能形成的最大十字,当min>1时代表当前十字合法。用一个vector记录下答案,扫一遍就可以找到所有十字。同时在开两个数组judgex与judgey,同样与字符数组一样大小,将十字一横中第一个格子judgex(i,j-min+1)加上一,将横中最后一个格子的下一个格子judgex(i,j+min)的值减一,同理将十字一竖中第一个格子judgey(i-min+1,j)加上一,将横中最后一个格子的下一个格子judgex(i+min,j)的值减一,同时分别对这两个数组求横向与纵向的前缀和,由此可以发现我们找的答案的十字中覆盖的值都大于0。

再进行一次扫描,如果图中当前位置为星号,且judgex与judgey的当前数值都为0,说明该星号不能被我们找到的答案中的十字中的任何一个覆盖,也就说明当前图不能完全被十字覆盖,不合法,输出-1,否则输出vector中记录下的答案。

#include <bits/stdc++.h>
 
using namespace std;
  
#define debug cout<<"???"<<endl
#define sync std::ios::sync_with_stdio(false)
#define ll long long
#define pb push_back
#define mp make_pair
#define MAXN 100005
#define INF 0x3f3f3f3f
#define frein freopen("input.txt", "r", stdin)
#define freout freopen("output.txt", "w", stdout)
char g[1005][1005];
int l[1005][1005],r[1005][1005],up[1005][1005],dn[1005][1005];
int jx[1005][1005],jy[1005][1005];
int n,m;
struct ans
{
    int x,y;
    int len;
};
vector <ans> p;
int main()
{
    //sync;
    //frein;
    //freout;
    scanf("%d%d",&n,&m);
    
    for(int i=1;i<=n;i++){
        scanf("%s",g[i]+1);
    }
    
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(g[i][j]=='*'){
                l[i][j]=l[i][j-1]+1;
                up[i][j]=up[i-1][j]+1;
            }
        }
    }
    
    for(int i=n;i>=1;i--){
        for(int j=m;j>=1;j--){
            if(g[i][j]=='*'){
                r[i][j]=r[i][j+1]+1;
                dn[i][j]=dn[i+1][j]+1;
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(g[i][j]=='*'){
                int len=INF;
                len=min(min(l[i][j],r[i][j]),
                        min(up[i][j],dn[i][j]));
                if(len>1){
                    ans temp;
                    temp.x=i;
                    temp.y=j;
                    temp.len=len-1;
                    p.pb(temp);
                    jx[i-len+1][j]++;
                    jx[i+len][j]--;
                    jy[i][j-len+1]++;
                    jy[i][j+len]--;
                }
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
        jx[i][j]+=jx[i-1][j];
        jy[i][j]+=jy[i][j-1];
        }
    }
 
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(g[i][j]=='*'&&jx[i][j]==0&&jy[i][j]==0){
                printf("-1\n");
                return 0;
            }
        }
    }
    int size=p.size();
    printf("%d\n",size);
    for(int i=0;i<size;i++){
        printf("%d %d %d\n",p[i].x,p[i].y,p[i].len);
    }
    return 0;
}

暴搜代码

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <vector>
#include <iostream>
#include <string>
#include <map>
#include <stack>
#include <cstring>
#include <queue>
#include <list>
#include <stdio.h>
#include <set>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <cctype>
#include <sstream>
#include <iterator>
#include <functional>
#include <stdlib.h>
#include <time.h>
#include <bitset>
using namespace std;

#define pi acos(-1)
#define s_1(x) scanf("%d",&x)
#define s_2(x,y) scanf("%d%d",&x,&y)
#define s_3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define s_4(x,y,z,X) scanf("%d%d%d%d",&x,&y,&z,&X)
#define s_5(x,y,z,X,Y) scanf("%d%d%d%d%d",&x,&y,&z,&X,&Y)
#define S_1(x) scan_d(x)
#define S_2(x,y) scan_d(x),scan_d(y)
#define S_3(x,y,z) scan_d(x),scan_d(y),scan_d(z)
#define PI acos(-1)
#define endl '\n'
#define srand() srand(time(0));
#define me(x,y) memset(x,y,sizeof(x));
#define foreach(it,a) for(__typeof((a).begin()) it=(a).begin();it!=(a).end();it++)
#define close() ios::sync_with_stdio(0); cin.tie(0);
#define FOR(x,n,i) for(int i=x;i<=n;i++)
#define FOr(x,n,i) for(int i=x;i<n;i++)
#define fOR(n,x,i) for(int i=n;i>=x;i--)
#define fOr(n,x,i) for(int i=n;i>x;i--)
#define W while
#define sgn(x) ((x) < 0 ? -1 : (x) > 0)
#define bug printf("***********\n");
#define db double
#define ll long long
#define mp make_pair
#define pb push_back
typedef long long LL;
typedef pair <int, int> ii;
const int INF = 0x3f3f3f3f;
const LL LINF = 0x3f3f3f3f3f3f3f3fLL;
const int dx[] = {-1, 0, 1, 0, 1, -1, -1, 1};
const int dy[] = {0, 1, 0, -1, -1, 1, -1, 1};
const int maxn = 1e3 + 10;
const int maxx = 1e4 + 10;
const double EPS = 1e-8;
const double eps = 1e-8;
const int mod = 1e9 + 7;
template <class T> inline T min(T a, T b, T c) {return min(min(a, b), c);}
template <class T> inline T max(T a, T b, T c) {return max(max(a, b), c);}
template <class T> inline T min(T a, T b, T c, T d) {return min(min(a, b), min(c, d));}
template <class T> inline T max(T a, T b, T c, T d) {return max(max(a, b), max(c, d));}
template <class T> inline bool scan_d(T &ret) {
    char c;
    int sgn;
    if (c = getchar(), c == EOF) return 0;
    while (c != '-' && (c < '0' || c > '9')) c = getchar();
    sgn = (c == '-') ? -1 : 1;ret = (c == '-') ? 0 : (c - '0');
    while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return 1;
}
inline bool scan_lf(double &num) {
    char in;
    double Dec = 0.1;
    bool IsN = false, IsD = false;
    in = getchar();
    if (in == EOF) return false;
    while (in != '-' && in != '.' && (in < '0' || in > '9')) in=getchar();
    if (in == '-') {IsN = true; num = 0;}
    else if (in == '.') {IsD = true; num = 0;}
    else num = in - '0';
    if (!IsD) {
        while (in = getchar(), in >= '0' && in <= '9') {num *= 10; num += in - '0';}
    }
    if (in != '.') {
        if (IsN) num = -num;
        return true;
    }
    else{
        while (in = getchar(), in >= '0' && in <= '9') {
            num += Dec * (in - '0');
            Dec *= 0.1;
        }
    }
    if (IsN) num = num;
    return true;
}
void Out(LL a) {if(a < 0) {putchar('-'); a = -a;}if(a >= 10) Out(a / 10); putchar(a % 10 + '0');}
void print(LL a) {Out(a), puts("");}
/**********************************************WHITE_YASHA**********************************************/
//freopen( "in.txt" , "r" , stdin );
//freopen( "data.txt" , "w" , stdout );
//cerr << "run time is " << clock() << endl;
struct node {
    int x, y, s;
    node() {}
    node(int _x, int _y, int _s) {
        x = _x;
        y = _y;
        s = _s;
    }
};
vector <node> v;
char g[maxn][maxn];
bool vis[maxn][maxn];
int n, m;
void solve(int x, int y) {
    int ans = 1, f = 1, flag = 0;
    W (f) {
        FOr (0, 4, i) {
            int xx = x + dx[i] * ans, yy = y + dy[i] * ans;
            if (xx < 0 || yy < 0 || xx >= n || yy >= m || g[xx][yy] != '*') {
                f = 0;
                break;
            }
        }
        if (f) {
            vis[x + dx[0] * ans][y + dy[0] * ans] = vis[x + dx[1] * ans][y + dy[1] * ans] = vis[x + dx[2] * ans][y + dy[2] * ans] = vis[x + dx[3] * ans][y + dy[3] * ans] = vis[x][y] = true;
            flag = 1;
            ans++;
        }
        else break;
    }
    if (flag) v.pb({x + 1, y + 1, ans - 1});
}
int main() {
    s_2(n, m);
    FOr (0, n, i) scanf("%s", g[i]);
    me(vis, false);
    FOr (0, n, i) FOr (0, m, j) {
        if (g[i][j] == '*') solve(i, j);
    }
    bool flag = true;
    FOr (0, n, i) {
        FOr (0, m, j) {
            //            printf("%d%s", vis[i][j], j == m - 1 ? "\n" : " ");
            if (g[i][j] == '*' && !vis[i][j]) {
                flag = false;
                break;
            }
        }
        if (!flag) break;
    }
    if (!flag || v.size() > n * m) printf("-1\n");
    else {
        printf("%d\n", (int)v.size());
        foreach (it, v) printf("%d %d %d\n", it -> x, it -> y, it -> s);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值