洛谷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 枚举左边界,向右枚举右边界,同时不断限制上下边界,最后右边界是整个图的边界: 由于没有做左边界是整个图的边 ...
随机推荐
- JavaScript面向对象:创建对象
1.初级创建对象 var oCar=new Object; oCar.color='red'; oCar.door=4; oCar.map=3; oCar.showColor=function () ...
- Message: 'chromedriver' executable needs to be available in the path.
环境:windows10 python:3.7.3 已经把 executable.exe 添加到了环境变量中,但还是会提示以上错误. 解决办法: from selenium import webdri ...
- LeetCode 677. Map Sum Pairs 键值映射(C++/Java)
题目: Implement a MapSum class with insert, and sum methods. For the method insert, you'll be given a ...
- android webview正确显示音标
package com.example.fonttest; import android.support.v7.app.ActionBarActivity; import android.webkit ...
- 关于JavaScript的DOM和BOM
本文探讨JavaScript的三大部分中的两个部分,DOM和BOM. DOM介绍 DOM,全称Document Object Model,即文档对象模型.它 是W3C的一个标准,定义了一个对文档操作的 ...
- qt creator源码全方面分析(2-6)
目录 User Interface Text Guidelines 语法和风格 标点 编写工具提示tooltips 编写消息 UI文本大写 使用书本样式大写 使用句子样式大写 准备本地化 标记UI文本 ...
- hdu 1159求最长公共子序列
题目描述:给出两个字符串,求两个字符串的公共子序列(不是公共子串,不要求连续,但要符合在原字符串中的顺序) in: abcfbc abfcab programming contest abcd mnp ...
- 2019ccpc哈尔滨打铜记
小学生日记: 2019.10.13,哈尔滨,打了个铜 开头 先说结论,这次失败,我的锅70%,sdl的锅5%,ykh25% Day0 周五, 我们队出现了奇怪的厄运上身 首先是我中途在飞机上数据线突然 ...
- bind() 理解 【转】
bind()可稍后执行 call() apply() 为了搞清这个陌生又熟悉的bind,google一下,发现javascript1.8.5版本中原生实现了此方法,目前IE9+,ff4+,chro ...
- 20200118--python学习第十一天
今日内容 函数小高级 lambda表达式 内置函数 内容回顾 1.函数基本结构 2.参数 形参 基本参数:def func(a1,a2):pass 默认值:def func(a1,a2=123):pa ...