jdoj 1740 卫星照片

题目描述:传送门

Description

农夫 John 正在研究他的农场的卫星照片.照片为一个R (1 <=
R <= 75) 行 C (1 <= C <= 75) 列的字符矩阵表示.如下图:
..................
..#####.......##..
..#####......##...
..................
#.......###.....#.
#.....#####.......
图上的一块相连通的 "#" 表示一群奶牛或一个房间, 两个子"#" 连通的意思是说左右或上下相连.而下面的两块则是分开的:
....
.#..
..#.
....
John现在根据卫星照片上的的这些"#"块的形状来判断哪些是牛群,哪些是房间.如果一个"#"块形状的边是水平或垂直的矩形,则是房间.其它的则认为都是牛群.在第一个图中,有三个房间 ( 2x1, 2x5, and 1x1)和2群牛.
请根据输入文件中的数据,统计出房间数和牛群数.

数据中牛群不会包围另一个牛群或房间.

Input

第一行,两个整数: R 和 C.
和 2..R+1行: 第 i+1 行表示照片的第 i 行情况,由 C 字符组成.

Output

* 第一行: 房间数.
* 第二行: 牛群数.

题目分析:

一道典型的搜索题;

方法一:我们可以先把图中所有的联通块都标记出来,然后再逐个判断当前联通块是否是一个矩形。
判断矩形的方法:我的方法比较暴力~~ 以当前点拓展出这个点最多能到达 上下左右四个位置  然后暴力两重循环判断是否为矩形 :需要满足在当前区域中没有 '.' 并且在这个区域中没有属于其他联通块的 '#'

为了避免某些奇怪的形状符合上述要求,却并不是一个矩形,所以需要对于每一个被第一遍搜索标记的联通块都check( )一遍,为了让当前这个联通块中的其他方块来更新我整个联通块的合法性

这里为了剪枝,将use[]数组分为3个类型:
1:use[i]=0; 表示当前联通块我还没有搜索到。
2:use[i]=1; 表示目前为止这个联通块是合法的
3:use[i]=-1;表示这个联通块不是合法的,这样的话当枚举判断时遇到use[i]=-1时可以直接跳过
当然,暴力嘛 时间复杂度自然就高 但是数据小2333

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
char s[100];
int n,m,ans;
int a[100][100];
int dx[5]={0,1,-1,0,0};
int dy[5]={0,0,0,1,-1};
int book[100][100];
struct your
{
    int x,y;
};
void bfs(int x,int y)
{
    queue<your>q;
    your nmp;
    nmp.x=x,nmp.y=y;
    q.push(nmp);
    book[x][y]=ans;
    while(q.size())
    {
        nmp=q.front();
        q.pop();
        for(int i=1;i<=4;i++)
        {
            int dxx=dx[i]+nmp.x;
            int dyy=dy[i]+nmp.y;
            if(dxx<1||dxx>n||dyy<1||dyy>m)
                continue;
            if(!book[dxx][dyy]&&a[dxx][dyy])
            {
                book[dxx][dyy]=ans;
                your temp;
                temp.x=dxx,temp.y=dyy;
                q.push(temp);
            }
        }
    }
}
int tmp;
int use[100];
void check(int x,int y)
{
    int dx1=x;int dx2=x;
    int dy1=y;int dy2=y;
    for(int i=x-1;i>=1;i--)
    {
        if(!a[i][y])break;
        dx1=i;
    } 
    for(int i=x+1;i<=n;i++)
    {
        if(!a[i][y])break;
        dx2=i;
    } 
    for(int i=y-1;i>=1;i--)
    {
        if(!a[x][i])break;
        dy1=i;
    }
    for(int i=y+1;i<=m;i++)
    {
        if(!a[x][i])break;
        dy2=i;
    }
    for(int i=dx1;i<=dx2;i++)
        for(int j=dy1;j<=dy2;j++)
            if(!a[i][j]||(a[i][j]&&(book[i][j]!=book[x][y])))
            {
                use[book[x][y]]=-1;
                break;
            }
    if(use[book[x][y]]==0)
        use[book[x][y]]=1;
    return ;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",&s[0]);
        for(int j=0;j<m;j++)
            if(s[j]=='#')a[i][j+1]=1;
    }   
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(!book[i][j]&&a[i][j]==1)
                ans++,bfs(i,j);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(book[i][j]&&use[book[i][j]]!=-1)
                check(i,j);
    for(int i=1;i<=ans;i++)
        if(use[i]==1)tmp++;
    printf("%d\n%d",tmp,ans-tmp);
}

方法二:时间复杂度高的原因是在于暴力判断矩形那部分 那么,我们可不可以一边搜索一边判断矩形?答案是肯定的。

据说Tonyzhao是这么做的(DFS) 可以来看一看~~

发完链接就跑路#滑稽

发表评论

邮箱地址不会被公开。 必填项已用*标注