首页 > 试题广场 >

剪纸游戏

[编程题]剪纸游戏
  • 热度指数:1222 时间限制:C/C++ 3秒,其他语言6秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
\hspace{15pt}小蓝拿着一张 n \times m 的方格纸从中剪下若干不相连的图案;剪裁时只会沿着方格网线裁切,因此不会破坏任何一个完整的小方格。

\hspace{15pt}小灰灰只拿到了剩余的残缺纸张。若用 `'.'` 表示被剪去的小方格,`'*'` 表示仍保留的小方格,则他得到一张由 `'.'` 与 `'*'` 组成的矩阵。由于各个剪下的图案之间互不连通,小灰灰可以根据 `'.'` 的连通块反推出每一个被剪下来的图案。

\hspace{15pt}现在小灰灰想知道:在所有被剪下来的图案中,有多少个是长方形(正方形视为特殊的长方形)。

输入描述:
\hspace{15pt}第一行输入两个整数 n,m\left(1\leqq n,m\leqq 1000\right)——纸张的行数与列数。
\hspace{15pt}接下来 n 行,每行输入一个长度为 m 的由 `'.'` 与 `'*'` 组成的字符串,描述残缺纸张的形状:
\hspace{23pt}\bullet\,`'.'` 代表该方格已被剪去;
\hspace{23pt}\bullet\,`'*'` 代表该方格仍保留。


输出描述:
\hspace{15pt}输出一个整数,表示被剪下来的图案中长方形的数量。
示例1

输入

4 10
*.*.*...**
...***.*..
.**..*.*..
*..*****..

输出

4

说明


可以看出,图中恰有一个正方形,三个长方形,共计四个长方形。
和前面迷宫类型的解题思路差不多,给加一个长方形的类型检查就ok了
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};

bool check_Rectangle(int &count, int &min_x, int &min_y, int &max_x, int &max_y, vector<string> &maze) {
    int rect_area = (max_x - min_x + 1) * (max_y - min_y + 1);
    if(rect_area != count) {
        return false;
    }

    for (int i = min_x; i <= max_x; i++) {
        for(int j = min_y; j < max_y; j++) {
            if(maze[i][j] != '.') {
                return false;
            }
        }
    }
    return true;
}

bool bfs(int i, int j, vector<string>& maze, vector<vector<bool>> &visited,
         int n, int m) {
    queue<pair<int, int>> q;
    q.push({i, j});
    visited[i][j] = true;

    //最小的坐标和最大的坐标
    int min_x = i, max_x = i, min_y = j, max_y = j;
    int count = 0;

    while (!q.empty()) {
        auto [x, y] = q.front();
        q.pop();
        count ++;
        min_x = min(min_x, x);
        min_y = min(min_y, y);
        max_x = max(max_x, x);
        max_y = max(max_y, y);

        for (int i = 0; i < 4; i++) {
            int nx = x + dx[i];
            int ny = y + dy[i];

            if(nx >= 0 && nx < n && ny >= 0 && ny < m &&
                visited[nx][ny] == false && maze[nx][ny] == '.') {
                    visited[nx][ny] = true;
                    q.push({nx, ny});
            }
        }
    }
    if(check_Rectangle(count, min_x, min_y, max_x, max_y, maze)) {
        return true;
    }else {
        return false;
    }
}

int main() {
    int n, m;
    cin >> n >> m;
    vector<string> maze(n);
    for (int i = 0; i < n; i++) {
        cin >> maze[i];
    }

    int sx = 0, sy = 0;
    int ex = n - 1, ey = m - 1;
    vector<vector<bool>> visited(n, vector<bool>(m, false));
    int rectangle_count = 0;
    for (int i = 0; i < n; i ++) {
        for (int j = 0; j < m; j++) {
            if (maze[i][j] == '.' && visited[i][j] == false) {
                if (bfs(i, j, maze, visited, n, m)) {
                    rectangle_count++;
                }
            }
        }
    }
    cout << rectangle_count << endl;

}
// 64 位输出请用 printf("%lld")

发表于 2025-10-30 11:16:44 回复(0)
#include <stdio.h>
#include <stdlib.h>

//来,这次得好好写单链表的队列。
//怎么判断是不是长方形:对 component_cells 列表中的所有坐标,找到它们行和列的最大值与最小值,从而确定这个图案的边界框 (Bounding Box)。
//找到最小最大的xy值计算边界框的理论面积,对比走过的格子是不是那么多就行。

//BFS需要队列,但是c语言需要自己写,恶心
typedef struct position{   //单链表队列
    int x;
    int y;
    int bushu;   //这个问题用不到最短路径的步数统计
    struct position*next;
}position,*positionlink;

positionlink queue;//队列

//入队列
void queue_push(positionlink* queue,positionlink temp){
    if (*queue==NULL) {  //判断指向的内容是否空队列
        *queue=temp;
    }else {
        positionlink p=(*queue);
        while (p->next!=NULL) {
            p=p->next;
        }
        p->next=temp;
    }
}

//出队列;
positionlink queue_pop(positionlink* queue)  //传队列的指针进来才不会是复制
{
    if(*queue==NULL){
        return *queue;
    }else {
        positionlink temp=*queue;
        *queue=(*queue)->next;
        temp->next=NULL;    //卧槽,原来是忘记断开连接了
        return  temp;
    }
}

//判断队列是否为空.为1时是空队列
int is_empty_queue(positionlink *queue)
{
    return (*queue)==NULL;
}

//显示队列情况
void show_queue(positionlink queue)
{
    positionlink t=queue;
    while(t!=NULL)
    {
        printf("x=%d,y=%d ---",t->x,t->y);
        t=t->next;//应该是t-next
    }
    printf("\n");
    
    return;
}

// 创建新节点,我丢不能利用栈上创建的节点加入队列啊,堆栈不能混用,因为栈上的局部变量会消失啊
positionlink create_node(int x, int y) {
    positionlink new_node = malloc(sizeof(position));
    if (new_node == NULL) {
        printf("Memory allocation failed!\n");
        exit(1);
    }
    new_node->x = x;
    new_node->y = y;
    new_node->bushu = 0;
    new_node->next = NULL;
    return new_node;
}
    
int main() {
    
    queue=NULL;  //初始化队列
    //测试队列
    // position temp={
    //     .x=6,
    //     .y=5,
    //     .bushu=10,
    //     .next=NULL
    // };

    // queue_push(&queue, &temp);
    // printf("empty=%d\n",is_empty_queue(queue));
    // positionlink  t=queue_pop(&queue);
    // printf("x=%d y=%d bushu=%d\n",t->x,t->y,t->bushu);
    
    //读取方格纸
    int n,m;
    scanf("%d %d",&n,&m);
    char **fangge=malloc(sizeof(char*)*n);
    

    for (int i=0;i<n; i++) {
        fangge[i]=malloc(sizeof(char)*(m+1));//加1保住/0
        scanf("%s",fangge[i]);
        //printf("%s\n",fangge[i]);
    }
    int changfang_count=0; //记录长方形个数
    //开始找图案
    for (int i=0; i<n; i++) {  //x轴
        for(int j=0;j<m;j++)
        {
            if(fangge[i][j]=='.')
            {
                //找图案,记录最小最大xy轴,和走过的方格个数
                int min_x=m,min_y=n,max_x=0,max_y=0,geshu=1;
                //初始位置入队列
                position temp={
                        .x=j,  //x是横的那个吧
                        .y=i,
                        .bushu=0,//本题好像不用记最短路径
                        .next=NULL
                };
                fangge[i][j]='*'; //阻塞
                queue_push(&queue,&temp);
                while (is_empty_queue(&queue)==0) {  //不为空表示队列没遍历完                    
                    positionlink tou=queue_pop(&queue); //拿到队列的头
                    //printf("取出的位置(%d,%d)\n",tou->x,tou->y);
                    //show_queue(queue);
                    //记录最小最大xy值,和走过的步数
                    if (tou->x<min_x) {
                        min_x=tou->x;
                    }
                    if (tou->x>max_x) {
                        max_x=tou->x;
                    }
                    //记录最小最大xy值
                    if (tou->y<min_y) {
                        min_y=tou->y;
                    }
                    if (tou->y>max_y) {
                        max_y=tou->y;
                    }

                    //看看往上下左右能不能走
                    if (tou->x-1>=0&&fangge[tou->y][tou->x-1]=='.') {     //往左                       
                        geshu++;//走过的个数
                        positionlink temp=create_node(tou->x-1, tou->y);
                        queue_push(&queue, temp);
                        fangge[tou->y][tou->x-1]='*';  //标记阻塞
                    }
                    if (tou->x+1<m&&fangge[tou->y][tou->x+1]=='.') {     //往右                       
                        geshu++;//走过的个数
                        positionlink temp=create_node(tou->x+1, tou->y);
                        queue_push(&queue, temp);
                        fangge[tou->y][tou->x+1]='*';  //标记阻塞
                    }
                    if (tou->y-1>=0&&fangge[tou->y-1][tou->x]=='.') {     //往上                       
                        geshu++;//走过的个数
                        positionlink temp=create_node(tou->x, tou->y-1);
                        queue_push(&queue, temp);
                        fangge[tou->y-1][tou->x]='*';  //标记阻塞
                    }
                    if (tou->y+1<n&&fangge[tou->y+1][tou->x]=='.') {     //往下                       
                        geshu++;//走过的个数
                        positionlink temp=create_node(tou->x, tou->y+1);
                        queue_push(&queue, temp);
                        fangge[tou->y+1][tou->x]='*';  //标记阻塞
                    }
                    
                     
                }

                //遍历结束后,计算是不是长方形
                int d=max_x-min_x+1;  //底的长度
                int h=max_y-min_y+1;  //高
                if (d*h==geshu) {       //理论长方形面积是否等于走过的方格个数
                    changfang_count++;
                }

            }else if (fangge[i][j]=='*') {  //跳过
                continue;
            }
        }
    }

    printf("%d",changfang_count);


    return 0;
}

发表于 2025-10-07 12:03:30 回复(0)
#include <iostream>
#include <queue>
#include <type_traits>
#include <vector>
using namespace std;
long long int n, m;
bool isvalid(int x, int y, vector<vector<bool>>& v) {
if (x >= 0 && x < n && y >= 0 && y < m && (v[x][y] == false))
return true;
else {
return false;
}
}
int main() {
int cnt = 0, yes = 0;
ios::sync_with_stdio(false);
cin >> n >> m;
vector<vector<char>> p(n, vector<char>(m));
for (int i = 0; i < n; i++) {
for (int k = 0; k < m; k++) {
char w;
cin >> w;
p[i][k] = w;
}
}
vector<vector<bool>> visit(n, vector<bool>(m, false));
int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
for (int i = 0; i < n; i++) {
for (int k = 0; k < m; k++) {
if (p[i][k] == '*' || visit[i][k] == true) {
continue;
}
queue<pair<int, int>> q;
q.push({i, k});
visit[i][k] = true;
int min_left = i;
int max_right = i;
int min_up = k;
int max_bot = k;
while (!q.empty()) {
int x = q.front().first;
int y = q.front().second;
q.pop();
cnt++;
for (int i = 0; i < 4; i++) {
int nx = x + dir[i][0];
int ny = y + dir[i][1];
if (isvalid(nx, ny, visit) && p[nx][ny] == '.') {
q.push({nx, ny});
visit[nx][ny] = true;
min_left = min(min_left, nx);
max_right = max(max_right, nx);
min_up = min(min_up, ny);
max_bot = max(max_bot, ny);

}
}

}
long long int area = (max_right - min_left + 1) * (max_bot - min_up + 1);
if (area == cnt) {
yes++;

}
cnt = 0;
}



}
cout << yes;

}
发表于 2025-09-10 23:23:41 回复(0)
/*
    for n // 从左往右
        for m // 从上往下
            BFS(i,j) 

    BFS(i,j)时,k[i][j]应该是长方形的左上角,记录最右的下标max_i、最下的下标max_j和'.'的数量num,判断(max_i+1-i)*(max_j+1-j) == num,但是有部分样例没通过。
    后面加上记录 min_i,min_j,然后判断(max_i+1 -min_i)*(max_j+1 -min_j) == num就都通过了。
*/
package main

import (
	"fmt"
)

type Node struct{
    i,j int
}

func main() {
    var n, m int
    fmt.Scanf("%d %d", &n, &m)
    var k = make([][]byte, n)
    var v = make([][]bool, n)
    var s string
    for i:=0;i<n;i++{
        k[i] = make([]byte, m)
        v[i] = make([]bool, m)
        fmt.Scanf("%s", &s)
        k[i] = []byte(s)
    }

    var result, num, max_i, max_j, ni, nj, min_i, min_j int
    var queue []Node
    var cur Node
    dist := [][]int{{1,0}, {-1,0}, {0,1}, {0,-1}}

    var BFS func(i, j int)
    BFS = func(i,j int){
        queue = []Node{{i,j}}
        for len(queue) > 0{
            cur = queue[0]
            queue =queue[1:]

            for _, d := range dist{
                ni = cur.i + d[0]
                nj = cur.j + d[1]
                if ni<0 || ni>=n ||nj<0||nj>=m||v[ni][nj]||k[ni][nj]=='*'{
                    continue
                }
                v[ni][nj] = true
                num++
                queue = append(queue, Node{ni,nj})
                if ni > max_i {
                    max_i = ni
                }
                if ni < min_i {
                    min_i = ni
                }
                if nj > max_j {
                    max_j = nj
                }
                if nj < min_j{
                    min_j = nj
                }
            }
        }
    }
    for i:=0;i<n;i++{
        for j:=0;j<m;j++{
            if k[i][j] == '.' && !v[i][j]{
                v[i][j] = true
                max_i = i
                max_j = j
                min_i = i
                min_j = j
                num = 1
                BFS(i,j)
                if (max_i+1 -min_i)*(max_j+1 -min_j) == num {
                    result++
                }
            }
        }
    }
    fmt.Print(result)
}

发表于 2025-09-07 20:05:02 回复(0)
奇怪了,为啥我这空间复杂度能有70m,传的不都是引用嘛
#include <climits>
#include <iostream>
#include <vector>
using namespace std;

//上下左右
int a,b,c,d;

int dfs(vector<string>& grid, int i, int j)
{
    int n = grid.size();
    int m = grid[0].size();
    if (i < 0 || i==n || j<0 || j==m || grid[i][j] != '.')
    {
        return 0;
    }
    int ans = 1;
    grid[i][j] = '*';
    a = max(a,i);
    b = min(b,i);
    c = min(c,j);
    d = max(d,j);
    ans += dfs(grid, i+1, j);
    ans += dfs(grid, i-1, j);
    ans += dfs(grid, i, j+1);
    ans += dfs(grid, i, j-1);
    return ans;
}
int main() {
    int n,m;
    cin >> n >> m;
    vector<string> grid(n);
    for (string& s : grid)
    {
        cin >> s;
    }

    int cnt = 0;
    for (int i = 0; i<n; ++i)
    {
        for (int j = 0; j<m; ++j)
        {
            if (grid[i][j] == '.')
            {
                a = d = INT_MIN;
                b = c = INT_MAX;
                int area = dfs(grid,i,j);
                if (area == (a-b+1)*(d-c+1))
                {
                    cnt++;
                }
            }
        }
    }
    cout << cnt;

发表于 2025-09-05 23:58:01 回复(0)
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
 int n,m;
vector<string> s;
vector<vector<bool>> visited;
bool bfs(int a,int b)
{
    int maxx=0,mayy=0;
    int mixx=1e9,miyy=1e9;
    queue<pair<int,int>> q;
    q.push({a,b});
    int count=1;
    visited[a][b]=true;
    while(!q.empty())
    {
        auto [x,y]=q.front();
        q.pop();
        maxx=max(maxx,x);
        mayy=max(mayy,y);
        mixx=min(mixx,x);
        miyy=min(miyy,y);
        for(int i=0;i<4;i++)
        {
            int nx=dx[i]+x;
            int ny=dy[i]+y;
            if(nx>=1 && nx<=n && ny>=1 && ny<=m &&!visited[nx][ny] &&s[nx][ny]=='.')
            {
                visited[nx][ny]=true;
                q.push({nx,ny});
                count++;
            }
        }
    }
    int area = (maxx - mixx + 1) * (mayy - miyy + 1);
    return count == area;
    
}




int main() {
   
    int ans=0;
    cin>>n>>m;
    s.resize(n+1);
    visited.resize(n+1,vector<bool>(m+1,false));
    for(int i=1;i<=n;i++)
    {
        cin>>s[i];
        s[i]=' '+s[i];
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(s[i][j]=='.' && !visited[i][j])
            {
             bool f=bfs(i,j);
                if(f) ans++;
            }
        }
    }
    cout<<ans<<endl;
     
}

发表于 2025-08-30 10:58:40 回复(0)