原题链接:https://www.luogu.com.cn/problem/P1331

简单来说就是给出一个由‘#’和‘.‘组成的矩阵。需要识别存在几个矩形(被完全填充的)。如果有矩形相互衔接则认为出错。

那么如何识别矩形呢?关于矩形的思考有以下的三种:

1、对于r行c列的矩阵,1表示有效0表示无效。以行优先的方式遍历,如果在点(i,k)处出现一个1则进行以下操作:k不变递增i直到i为0作边界。获取第i行的长度len并遍历i+1以后有效的每一行,依次确定长度是否与len相等即可。实现的代码如下:

 bool check(int x,int y)
{
int endx=x;
while(endx<r&&aim[endx][y])endx++;
//遍历行边界
int i=x;
int k=y;
while(k<c&&aim[i][k]){aim[i][k]=;k++;}
int endy = k;
//遍历第一行的列边界
for(i++;i<endx;i++)
{//控制行
for(k=y;k<c;k++)
{//控制列
if(!aim[i][k])break;
aim[i][k]=;
}
if(k!=endy)return false;
//注意是不等于
}
return true;
} int solve()
{
int couts=;
for(int i=;i<r;i++)
{
for(int k=;k<c;k++)
{
if(aim[i][k])
{
if(check(i,k))couts++;
else return -;
}
}
}
return couts;
}

但是,有时候的情况并不允许,例如:(0->'.'&&1->'#')


该思路重视左边界与矩形内部,但是左边界往往不能够照应到整个连通区,所以方案不允许。

2、第二种方案是采用搜索的方式关注了矩形的坐标意义--即四个顶点的坐标关系。具体实现方式就是BFS遍历获取连通块的最极端的四个点后,再比较四个点的几何关系。具体代码如下:

 struct point
{
int x,y;
};
int r,c;
int aim[][];
const int dx[]={,,,-};
const int dy[]={,-,,};
int tx[];
int ty[]; bool check(int x,int y)
{
queue<point> psd;
point p;
p.x=x; p.y=y; psd.push(p);
int nowx,nowy;
while()
{
if(psd.empty())break;
p=psd.front();psd.pop();
nowx=p.x; nowy=p.y;
if(aim[nowx][nowy]==)continue;
aim[nowx][nowy]=;
//printf("(%d,%d)\n",nowx,nowy);
if(tx[]>=nowx&&ty[]>=nowy){tx[]=nowx;ty[]=nowy;}//左上角
if(tx[]>=nowx&&ty[]<=nowy){tx[]=nowx;ty[]=nowy;}//右上角
if(tx[]<=nowx&&ty[]>=nowy){tx[]=nowx;ty[]=nowy;}//左下角
if(tx[]<=nowx&&ty[]<=nowy){tx[]=nowx;ty[]=nowy;}//右下角
for(int i=;i<;i++)
{
int cx=nowx+dx[i];
int cy=nowy+dy[i];
if(cx>=&&cy>=&&cx<r&&cy<c&&aim[cx][cy])
{
p.x=cx;p.y=cy;psd.push(p);
}
}
}
/*for(int i=0;i<4;i++)
{
printf("tx[%d]=%d,ty[%d]=%d\n",i,tx[i],i,ty[i]);
}*/
bool ok;
ok=(ty[]==ty[])&&(ty[]==ty[]);
ok=ok&&(tx[]==tx[])&&(tx[]==tx[]);
return ok;
}

该方案仍然错误,因为对于任何一个矩形边框它都可以认为边框是合法的。也就是说该算法忽略了矩形的内部。

3、第二种方案其实基本上摸清了矩形的特征,只要解决“边框”问题就可以。也就是说要保证BFS遍历过的点数。其实只需要增加一个点数计数变量pointnum即可。BFS后直接根据四个顶点的坐标计算出应有的点的个数,比较即可。于是将上述代码更改如下:

 #include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
struct point
{
int x,y;
};
int r,c;
int aim[][];
const int dx[]={,,,-};
const int dy[]={,-,,};
int tx[];
int ty[]; bool check(int x,int y)
{
int pointnum=;
queue<point> psd;
point p;
p.x=x; p.y=y; psd.push(p);
int nowx,nowy;
while()
{
if(psd.empty())break;
p=psd.front();psd.pop();
nowx=p.x; nowy=p.y;
if(aim[nowx][nowy]==)continue;
aim[nowx][nowy]=;
//printf("(%d,%d)\n",nowx,nowy);
pointnum++;
if(tx[]>=nowx&&ty[]>=nowy){tx[]=nowx;ty[]=nowy;}//左上角
if(tx[]>=nowx&&ty[]<=nowy){tx[]=nowx;ty[]=nowy;}//右上角
if(tx[]<=nowx&&ty[]>=nowy){tx[]=nowx;ty[]=nowy;}//左下角
if(tx[]<=nowx&&ty[]<=nowy){tx[]=nowx;ty[]=nowy;}//右下角
for(int i=;i<;i++)
{
int cx=nowx+dx[i];
int cy=nowy+dy[i];
if(cx>=&&cy>=&&cx<r&&cy<c&&aim[cx][cy])
{
p.x=cx;p.y=cy;psd.push(p);
}
}
}
bool ok;
ok=(ty[]==ty[])&&(ty[]==ty[]);
ok=ok&&(tx[]==tx[])&&(tx[]==tx[]);
int s=(ty[]-ty[]+)*(tx[]-tx[]+);
ok=ok&&(s==pointnum);
//printf("pointnum->%d\n",pointnum);
return ok;
} int solve()
{
int couts=;
for(int i=;i<r;i++)
{
for(int k=;k<c;k++)
{
if(aim[i][k])
{
for(int p=;p<;p++)
{
tx[p]=i;ty[p]=k;
}
if(check(i,k))couts++;
else return -;
}
}
//printf("ok\n");
}
return couts;
} int main()
{
//freopen("input.txt","r",stdin);
while(cin>>r>>c)
{
memset(aim,,sizeof(aim));
getchar();
for(int i=;i<r;i++)
{
for(int k=;k<c;k++)
{
char m;cin>>m;
if(m=='#')aim[i][k]=;
}
getchar();
}
for(int i=;i<r;i++)
{
for(int k=;k<c;k++)
{
if(aim[i][k])printf("");
else printf("");
}
printf("\n");
}
printf("\n");
//
int num=solve();
if(num==-)printf("Bad placement.\n");
else printf("There are %d ships.\n",num);
/*for(int i=0;i<r;i++)
{
for(int k=0;k<c;k++)
{
if(aim[i][k])printf("%2d",1);
else printf(" ");
}
printf("\n");
}
printf("\n");*/
}
return ;
}

提交后完美解决。

 #include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
struct point
{
int x,y;
};
int r,c;
int aim[][];
const int dx[]={,,,-};
const int dy[]={,-,,};
int tx[];
int ty[]; bool check(int x,int y)
{
int pointnum=;
queue<point> psd;
point p;
p.x=x; p.y=y; psd.push(p);
int nowx,nowy;
while()
{
if(psd.empty())break;
p=psd.front();psd.pop();
nowx=p.x; nowy=p.y;
if(aim[nowx][nowy]==)continue;
aim[nowx][nowy]=;
pointnum++;
if(tx[]>=nowx&&ty[]>=nowy){tx[]=nowx;ty[]=nowy;}//左上角
if(tx[]>=nowx&&ty[]<=nowy){tx[]=nowx;ty[]=nowy;}//右上角
if(tx[]<=nowx&&ty[]>=nowy){tx[]=nowx;ty[]=nowy;}//左下角
if(tx[]<=nowx&&ty[]<=nowy){tx[]=nowx;ty[]=nowy;}//右下角
for(int i=;i<;i++)
{
int cx=nowx+dx[i];
int cy=nowy+dy[i];
if(cx>=&&cy>=&&cx<r&&cy<c&&aim[cx][cy])
{
p.x=cx;p.y=cy;psd.push(p);
}
}
}
bool ok;
ok=(ty[]==ty[])&&(ty[]==ty[]);
ok=ok&&(tx[]==tx[])&&(tx[]==tx[]);
int s=(ty[]-ty[]+)*(tx[]-tx[]+);
ok=ok&&(s==pointnum);
return ok;
} int solve()
{
int couts=;
for(int i=;i<r;i++)
{
for(int k=;k<c;k++)
{
if(aim[i][k])
{
for(int p=;p<;p++)
{
tx[p]=i;ty[p]=k;
}
if(check(i,k))couts++;
else return -;
}
}
}
return couts;
} int main()
{
while(cin>>r>>c)
{
memset(aim,,sizeof(aim));
getchar();
for(int i=;i<r;i++)
{
for(int k=;k<c;k++)
{
char m;cin>>m;
if(m=='#')aim[i][k]=;
}
getchar();
}
//
int num=solve();
if(num==-)printf("Bad placement.\n");
else printf("There are %d ships.\n",num);
}
return ;
}

提交的代码

OK

洛谷P1331-搜索基础-什么是矩形?(我的方案)的更多相关文章

  1. 洛谷 P3187 BZOJ 1185 [HNOI2007]最小矩形覆盖 (旋转卡壳)

    题目链接: 洛谷 P3187 [HNOI2007]最小矩形覆盖 BZOJ 1185: [HNOI2007]最小矩形覆盖 Description 给定一些点的坐标,要求求能够覆盖所有点的最小面积的矩形, ...

  2. 洛谷P1331海战

    题目描述 在峰会期间,武装部队得处于高度戒备.警察将监视每一条大街,军队将保卫建筑物,领空将布满了F-2003飞机.此外,巡洋船只和舰队将被派去保护海岸线. 不幸的是因为种种原因,国防海军部仅有很少的 ...

  3. 洛谷——P1331 海战

    P1331 海战 题目描述 在峰会期间,武装部队得处于高度戒备.警察将监视每一条大街,军队将保卫建筑物,领空将布满了F-2003飞机.此外,巡洋船只和舰队将被派去保护海岸线.不幸的是因为种种原因,国防 ...

  4. 海战(洛谷 P1331)

    题目描述 在峰会期间,武装部队得处于高度戒备.警察将监视每一条大街,军队将保卫建筑物,领空将布满了F-2003飞机.此外,巡洋船只和舰队将被派去保护海岸线.不幸的是因为种种原因,国防海军部仅有很少的几 ...

  5. 洛谷P1884 [USACO12FEB]Overplanting S (矩形切割)

    一种矩形切割的做法: 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const in ...

  6. 洛谷 P1331 海战

    传送门 题解:由于船是方形的,所以比较简单.但是考试的时候跪了,orz.忘了考虑类似一圈井号中间有一摊水.          可以只考虑这个点上方和左边点的情况,这样分为四种情况.一种是左边是一滩水, ...

  7. 洛谷P1331 海战 题解

    题目传送门 思路 肯定食用dfs啦... 但关键是两条船接触了怎么判断呢?? 上图: 可以发现一下规律 当两条船接触时,必有一条直线连续穿过两条船 当一条船不与另一条船接触时,没有一条直线连续穿过两条 ...

  8. 洛谷P1331 海战

    海战 题目链接 这还是一道联通块的题,只是需要判断是否存在以下四种情况: o. .o oo oo oo oo o. .o 如果存在就是Bad placement. 要注意标记以下,不然会出现多次输出B ...

  9. 洛谷 P1578 奶牛浴场 —— 最大子矩形

    题目:https://www.luogu.org/problemnew/show/P1578 枚举左边界,向右枚举右边界,同时不断限制上下边界,最后右边界是整个图的边界: 由于没有做左边界是整个图的边 ...

随机推荐

  1. C语言博客作业6

    本周作业头 这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 作业链接 我在这个课程的目标是 熟悉多分支结构.字符型数据类型和逻辑运算符 这个作业在那个具体方面帮助我实现目标 完成pta作 ...

  2. ElasticSearch快速入门

    知识储备 学习ElasticSearch之前可以先了解一下lucene,这里是我整理的一篇关于lucene的笔记(传送门),对搜索框架有兴趣的还可以了解一下另一款企业级搜索应用服务器---solr(传 ...

  3. 【故障公告】再次遭遇SQL语句执行超时引发网站首页访问故障

    非常抱歉,昨天 18:40~19:10 再次遭遇上次遇到的 SQL 语句执行超时引发的网站首页访问故障,由此您带来麻烦,请您谅解. 上次故障详见故障公告,上次排查下来以为是 SQL Server 参数 ...

  4. 使用visual studio 2013读取.mat文件

    现在有一个T.mat 文件需要在c++中处理然后以.mat 或是.txt形式返回 T.mat中存储了十个cell,每个cell中会有一个不等长的数组 1.以下是相关配置过程: 参考:http://we ...

  5. DOCKER 学习笔记8 Docker Swarm 集群搭建

    前言 在前面的文章中,已经介绍如何在本地通过Docker Machine 创建虚拟Docker 主机,以及也可以在本地Windows 创建虚拟主机,也是可以使用的.这一节,我们将继续学习 Docker ...

  6. EMC networker nmm can restore and recover sqlserver as different name to different location

    EMC networker nmm can restore and recover sqlserver as different name to different location That is ...

  7. layui父子页面方法互调

    父级页面调用子页面方法 layer.open({ type: 2, content: 'test/iframe.html', success: function(layero, index){ var ...

  8. [信息安全] 05 X.509 公钥证书的格式标准

    X.509是# 公钥证书的格式标准, 广泛用于TLS/SSL安全通信或者其他需要认证的环境中.X.509证书可以由# CA颁发,也可以自签名产生. 1 Overview {#1-overview} X ...

  9. Mysql的基本查询语句

    聚集函数 mysql有5个聚集函数,分别是AVG,MAX,MIN,SUM,COUNT. 分组 分组的使用group by作为关键字,having作为条件关键字. having和where的区别:1.w ...

  10. MySQL复制(四)—多源(主)复制

    (一)多主复制概述 MySQL从5.7版本开启支持多主复制,所谓多主复制,是将多个主库的数据复制到一个从库中.通常用于数据仓库整合数据,比如OLTP系统为了分散业务压力,对数据库进行分库分表,当要对数 ...