洛谷P1331-搜索基础-什么是矩形?(我的方案)
原题链接: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-搜索基础-什么是矩形?(我的方案)的更多相关文章
- 洛谷 P3187 BZOJ 1185 [HNOI2007]最小矩形覆盖 (旋转卡壳)
题目链接: 洛谷 P3187 [HNOI2007]最小矩形覆盖 BZOJ 1185: [HNOI2007]最小矩形覆盖 Description 给定一些点的坐标,要求求能够覆盖所有点的最小面积的矩形, ...
- 洛谷P1331海战
题目描述 在峰会期间,武装部队得处于高度戒备.警察将监视每一条大街,军队将保卫建筑物,领空将布满了F-2003飞机.此外,巡洋船只和舰队将被派去保护海岸线. 不幸的是因为种种原因,国防海军部仅有很少的 ...
- 洛谷——P1331 海战
P1331 海战 题目描述 在峰会期间,武装部队得处于高度戒备.警察将监视每一条大街,军队将保卫建筑物,领空将布满了F-2003飞机.此外,巡洋船只和舰队将被派去保护海岸线.不幸的是因为种种原因,国防 ...
- 海战(洛谷 P1331)
题目描述 在峰会期间,武装部队得处于高度戒备.警察将监视每一条大街,军队将保卫建筑物,领空将布满了F-2003飞机.此外,巡洋船只和舰队将被派去保护海岸线.不幸的是因为种种原因,国防海军部仅有很少的几 ...
- 洛谷P1884 [USACO12FEB]Overplanting S (矩形切割)
一种矩形切割的做法: 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const in ...
- 洛谷 P1331 海战
传送门 题解:由于船是方形的,所以比较简单.但是考试的时候跪了,orz.忘了考虑类似一圈井号中间有一摊水. 可以只考虑这个点上方和左边点的情况,这样分为四种情况.一种是左边是一滩水, ...
- 洛谷P1331 海战 题解
题目传送门 思路 肯定食用dfs啦... 但关键是两条船接触了怎么判断呢?? 上图: 可以发现一下规律 当两条船接触时,必有一条直线连续穿过两条船 当一条船不与另一条船接触时,没有一条直线连续穿过两条 ...
- 洛谷P1331 海战
海战 题目链接 这还是一道联通块的题,只是需要判断是否存在以下四种情况: o. .o oo oo oo oo o. .o 如果存在就是Bad placement. 要注意标记以下,不然会出现多次输出B ...
- 洛谷 P1578 奶牛浴场 —— 最大子矩形
题目:https://www.luogu.org/problemnew/show/P1578 枚举左边界,向右枚举右边界,同时不断限制上下边界,最后右边界是整个图的边界: 由于没有做左边界是整个图的边 ...
随机推荐
- Intellij IDEA使用(一)项目模板类型
概述 IDEA默认打开后,会出现欢迎页面,可以选择打开Project的方式. 对于新建的Project,一般会选择[Create New Project],对于界面中,众多的Project类型,有时候 ...
- 使用.NET Core优雅获取并展示最新疫情数据
前言 新型冠状病毒的出现,着实让人紧张.我每天一大早都会去查看今天的最新数据,可是每次的数据都挺让人揪心的.今天突然间很想看看过去的历史的数据,结果查了很多资料都不是很全.反正国家让我们待在家里做贡献 ...
- Spring Boot 2.x基础教程:使用国产数据库连接池Druid
上一节,我们介绍了Spring Boot在JDBC模块中自动化配置使用的默认数据源HikariCP.接下来这一节,我们将介绍另外一个被广泛应用的开源数据源:Druid. Druid是由阿里巴巴数据库事 ...
- pyhon学习Day18--继承
[知识点] 面向对象的三大特性:继承.多态.封装 [继承] (1)继承:class Person(Animal): ——括号里的:父类,基类,超类 括号外的:子类,派生类 class Animal ...
- jsp:useBean 不能编译成class或者没有class这个属性
bean.jsp <%-- JSP学习笔记 --%> <%@ page contentType="text/html;charset=UTF-8" languag ...
- RT600 I2S外设介绍及应用
恩智浦的i.MX RT600是跨界处理器产品,同样也是i.MX RTxxx系列的开山之作.不同于i.MX RT1xxx系列单片机,i.MX RT600 采用了双核架构,将新一代Cortex-M33内核 ...
- Exchange邮件服务器安全
Exchange是由微软推出的用于企业环境中部署的邮件服务器.Exchange在逻辑上分为三个层次:网络层(network layer).目录层(directory layer).消息层(messag ...
- 视觉slam十四讲第七章课后习题7
版权声明:本文为博主原创文章,转载请注明出处:http://www.cnblogs.com/newneul/p/8544369.html 7.题目要求:在ICP程序中,将空间点也作为优化变量考虑进来 ...
- Grafana & Graphite & Collectd:监控系统
简介 监控是运维工作中的一个重要组成部分,今天介绍一套新的监控工具,方便好用,扩展性强,这套工具有三个组件,Grafana & Graphite & Collectd: Grafana ...
- Go语言实现:【剑指offer】旋转数组的最小数字
该题目来源于牛客网<剑指offer>专题. 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3, ...