原题链接: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. .net core3.1 webapi + element-ui upload组件实现文件上传

    首先,先看我个人的的项目结构. 这个webapi项目是专门用来做图片上传,其中分为两个控制器:单图片上传和多图片上传.而我接下来主要讲的还是单文件上传,对于多文件的上传,我暂且尚未研究成功. 其中pi ...

  2. Serverless 的资源评估与成本探索

    Serverless 布道师在讲解 Serverless 架构和云主机等区别的时候,总会有类似的描述: 传统业务开发完成想要上线,需要评估资源使用.根据评估结果,购买云主机,并且需要根据业务的发展不断 ...

  3. 位运算在状态压缩DP中的应用

    一.判断一个数字X的i位是不是1 方法:   << (i-)) & x > )  原理: 1左移(i-1)位,相当于制造了一个就i位上是1其他位都是0的一个二进制数.将这个数 ...

  4. 【原创】(二)Linux进程调度器-CPU负载

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  5. 牛客练习赛39 C 流星雨 (概率dp)

    题意: 现在一共有n天,第i天如果有流星雨的话,会有wi颗流星雨. 第1天有流星雨的概率是p1. 如果第i−1 (i≥2)天有流星雨,第i天有流星雨的可能性是pi+P,否则是pi. 求n天后,流星雨颗 ...

  6. Android View的绘制机制前世今生---前世

    就像上个文章说的,触摸事件的传递机制是从外层到内层的过程. 我们想来看看这个页面里面的层级关系: 以下我们就用what-how-why三部曲的方式来分析View的绘制过程. 由于篇幅很大,所以分几篇来 ...

  7. Html / XHtml 解析 - Parsing Html and XHtml

    Html / XHtml 解析 - Parsing Html and XHtml HTMLParser 模块 通过 HTMLParser 模块来解析 html 文件通常的做法是, 建立一个 HTMLP ...

  8. Andriod you must restart adb and eclipse

    今天看着视频 学习着 andriod ,启动 的时候 竟然报错 我试了N种google来的方法,都失效,现在把我的解决方法告诉大家,希望能帮到大家. 首先,我先罗列下我搜到的方法,大家也可以尝试. 1 ...

  9. 校招必看硬核干货:C++怎么学才能进大厂

    目录 关于小猿 如何找资料 自我定位 岗位需求 学习路线及时间安排 资料获取方式 C++语言在历史舞台上出现了不短的时间,虽然一直面临着Python,Go等新语言的挑战,但它在基础架构和大型软件上的优 ...

  10. Java开发最佳实践(一) ——《Java开发手册》之"编程规约"

    Java开发手册版本更新说明 专有名词解释 一. 编程规约 (一) 命名风格 (二) 常量定义 (三) 代码格式 (四) OOP 规约 (五) 集合处理 (六) 并发处理 (七) 控制语句 (八) 注 ...