boj 407 第一次排位赛训练d bfs 找联通矩阵 最大正方形
来源:互联网 发布:值得买源码 编辑:程序博客网 时间:2024/06/07 06:38
其实今天我又回看了这道题,这题用bfs时间花销很大,内存也开得很大,而且也许当时我写得不够好,运行了300ms,所以今天我把题目仔细看了一遍,学习了别人的方法以后,发现这题可以用别的方法来做(bfs技术含量太高了,其实完全不需要,遍历就可以)
于是我找出了当时考试的时候我没有通过的代码,以此为模板进行修改,代码将粘贴在后面,时间缩减到了57ms,内存更是缩小了三分之二。这题主要考的是逻辑,算法其实没什么特殊的。是我自己想复杂了,把它和校赛的另外一题弄混了,在最后我将给出校赛的题,求最大完美1矩阵
http://code.bupt.edu.cn/problem/p/407/
bfs 会用到往四个方向找 注意可以这样写 这个在迷宫里也有用到
注意里面外面都是'{'号,不要写成'(' ;
int ah[2][2] = {(-1,0), (0,1)}; 这样写是错误的
int ah[4][2] = {{-1,0}, {0,1}, {1,0}, {0,-1}};
vis[j+ah[i][0]][k+ah[i][1]]
407. BLOCKS
题目描述
给定一个
输入格式
有多组数据,EOF结束。
输出格式
每行对应一个answer
输入样例
6 8.....#.###.....###.....#.......##......##..#...#6 8.....#.###.....####...##.......###.....##..#...#
输出样例
There are 5 ships.So Sad
方法一 先要建一个sum数组,然后用bfs找连通块,找到以后再判断,是否是个矩形,不是直接退出,是的话记录访问过,继续寻找
#include <iostream>#include <cstdio>#include <string.h>#include <vector>#include <cmath>#include <algorithm>#include <queue>using namespace std;int n, m;char a[1005][1005];//储存字符int b[1005][1005];//字符转化为数字,‘#’为1,其它为0int vis[1005][1005];int sum[1005][1005];//统计左上角到当前位置总数,用于判断一个矩形是否是全为1的矩形queue <pair<int, int> > q;int ans;//存放结果,符合条件矩形个数int mini, minj, maxi, maxj;//一块连通区域的左上角与右下角(如果确实是符合条件的矩形的话)void bfs()//广度搜索,找连通都是1的区域{ int ai[4] = {-1, 0, 1, 0}; int aj[4] = {0, 1, 0, -1}; while(!q.empty()) { pair<int,int> tmp=q.front(); q.pop(); int j = tmp.first; int k = tmp.second; for (int i=0; i<4; i++) { if (((j+ai[i])<=0)||((j+ai[i])>n)||((k+aj[i])<=0)||((k+aj[i])>m)) continue;//越界 else if (vis[j+ai[i]][k+aj[i]]) continue;//已被访问 else if (!b[j+ai[i]][k+aj[i]])//为0,所以不符合,标记为访问过,跳过 { vis[j+ai[i]][k+aj[i]] = 1; continue; } else//符合条件加入队列 { vis[j+ai[i]][k+aj[i]] = 1; q.push(make_pair(j+ai[i], k+aj[i])); minj = min(k+aj[i], minj); maxj = max(k+aj[i], maxj); mini = min(j+ai[i], mini); maxi = max(j+ai[i], maxi); } } }}int main(){ while(~scanf("%d %d",&n,&m)) { ans = 0; memset(a, 0, sizeof a); memset(b, 0, sizeof b); memset(sum, 0, sizeof sum); memset(vis, 0, sizeof vis); for (int j=0; j<n; j++) { scanf("%s", a[j]); } for (int j=1; j<=n; j++) { for (int k=1; k<=m; k++) { if (a[j-1][k-1]=='#') b[j][k] = 1; else b[j][k] = 0; sum[j][k] = sum[j-1][k]+sum[j][k-1]-sum[j-1][k-1]+b[j][k]; //统计左上角到当前位置总数,用于判断一个矩形是否是全为1的矩形 } } int flag = 0; for (int j=1; j<=n; j++) { for (int k=1; k<=m; k++) { if (vis[j][k]) continue; if (!b[j][k]) { vis[j][k] = 1; continue; } while(!q.empty()) q.pop(); q.push(make_pair(j, k)); mini=maxi=j; minj=maxj=k; bfs(); int temp = sum[maxi][maxj]-sum[mini-1][maxj]-sum[maxi][minj-1]+sum[mini-1][minj-1]; //(mini, minj)到(maxi, maxj)的矩形如果都为1的值理想值与现实值的比较 if (temp==(maxi-mini+1)*(maxj-minj+1)) ans++; else { flag=1; break; } } if (flag) break; } if (flag) printf("So Sad\n"); else printf("There are %d ships.\n", ans); } return 0;}
方法二 直接遍历
#include <iostream>#include <cstdio>#include <string.h>#include <vector>#include <cmath>#include <algorithm>using namespace std;int n, m;char a[1005][1005];int b[1005][1005];bool vis[1005][1005];int tempn, tempm;int ans;int cap(int j, int k){ tempn=0, tempm=0; for (int q=k; q<=m; q++) if (b[j][q]&&b[j-1][q])//考虑上面有没有多余的# return 0; else if (b[j][q]) tempm++; else break; for (int p=j; p<=n; p++) { if (b[p][k]&&b[p][k-1])//考虑左边有没有多余的# return 0; else if (!b[p][k]) break;//考虑是不是能往下推进一行 else tempn++; for (int q=k+1; q<=k+tempm-1; q++) { if (!b[p][q]) return 0;//考虑推进的这一行是否整排都符合 } if (b[p][k+tempm]) return 0;//考虑这一行的尾部是否多出了一个#,其实这里不要应该也可以吧,因为下次出现时会先考虑是否左边有多余的# } for (int q=k; q<=k+tempm-1; q++)//考虑末行的下一行是否有多余的#,当然这里也不用考虑,因为只要新出现一个#我们会考虑这一排的上面是否曾经出现过# if (b[j+tempn][q]) return 0; for (int p=j; p<=j+tempn-1; p++) for (int q=k; q<=k+tempm-1; q++) vis[p][q] = 1; ans++; return 1;}int main(){ while(~scanf("%d %d", &n, &m)) { ans = 0; memset(a, 0, sizeof a); memset(vis, 0, sizeof vis); memset(b, 0, sizeof b); for (int j=0; j<n; j++) scanf("%s", a[j]); for (int j=1; j<=n; j++) for (int k=1; k<=m; k++) b[j][k] = a[j-1][k-1]=='#' ? 1 : 0; int flag = 1; for (int j=1; (j<=n)&&flag; j++) for (int k=1; (k<=m)&&flag; k++) { if (vis[j][k]||(!b[j][k])) continue; if (!cap(j, k)) flag = 0; } if (!flag) printf("So Sad\n"); else printf("There are %d ships.\n", ans); } return 0;}
校赛题
http://code.bupt.edu.cn/problem/p/382/点击打开链接 这道题如果有时间还要好好研究一下,因为算法的复杂富
382. Largest Square
题目描述
Give you a N*N(
输入格式
The first line is an integer
输出格式
For each case,output an integer which is the lenth of the side of the largest red square.
输入样例
231010001113111111111
输出样例
13
#include <algorithm>#include<iostream>#include<cstdio>#include<string.h>#include<vector> using namespace std;char a[2005][2005];int sum[2005][2005];int father[2005];int maxt;int l;int flag;void cap(int i, int j, int lt){ int temp; int p; temp = sum[i][j]-sum[i-lt][j]-sum[i][j-lt]+sum[i-lt][j-lt]; if (temp == lt*lt)//说明最大值大于等于l { flag = 1; maxt = (maxt>lt?maxt:lt); p = (father[lt]+lt)/2; } else if (!flag) { p = lt/2; } else p = (father[lt]+lt)/2; if (p == lt) return; father[p] = lt; cap(i, j, p); }int main(){ int num; scanf("%d", &num); for (int i=0; i<num; i++) { int N; scanf("%d", &N); memset(a, 0, sizeof a); memset(sum, 0, sizeof sum); //memset(value, 0, sizeof value); for (int j=0; j<N; j++) { scanf("%s", a[j]); } for (int j=1; j<=N; j++) { for (int k=1; k<=N; k++) { sum[j][k] = sum[j-1][k]+sum[j][k-1]-sum[j-1][k-1]+a[j-1][k-1]-'0'; } } l = 0; maxt = 0; int temp; for (int j=1; j<=N; j++) { for (int k=1; k<=N; k++) { if (a[j-1][k-1]=='0') continue; memset(father, 0, sizeof father); flag = 0; l = (j<k?j:k); father[l] = l; cap(j, k, l); } } printf("%d\n", maxt); } return 0;}
- boj 407 第一次排位赛训练d bfs 找联通矩阵 最大正方形
- 找最大的正方形
- 01矩阵最大正方形
- 最大正方形子矩阵
- 2D矩阵求最大正方形子矩阵,各项元素为1
- 2163 最大正方形子矩阵
- 矩阵动归--最大正方形
- wikioi 1259 最大正方形子矩阵
- vojos 1055,1057 最大子矩阵、正方形
- 0 1 矩阵查找最大正方形
- DP hdu1505 找最大矩阵
- 寒假训练--dfs+bfs--找朋友
- 最大正方形
- 最大正方形
- 最大正方形
- 最大正方形
- 最大正方形
- 最大正方形
- IOS7 MPMoviePlayerViewController横屏显示
- Eclipse背景颜色
- POJ 3259 Wormholes(Bellman_Ford判负圈)
- 拓扑排序算法
- 学习笔记二
- boj 407 第一次排位赛训练d bfs 找联通矩阵 最大正方形
- 剑指offer---二叉搜索树的实现(重点是删除)
- 各种基本数据结构和算法总结清单
- WIN 32 文本
- winform datetimepacker 开始日期 结束日期
- MFC如何使用开源Scintilla库?自动源码质量控制软件 iCode 编写全记录(一)
- jdk1.6官网下载地址
- 2.2阶乘(N!)
- HDU1536 SG博弈+尼姆博弈