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]]

时间限制 1000 ms 内存限制 65536 KB

题目描述

给定一个NM的矩阵,求问里面有多少个由'#'组成的矩形,"There are 5 ships.",若是里面有一个不是矩形的联通块,则输出"So Sad"

输入格式

1n,m1000

有多组数据,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

时间限制5000 ms内存限制 65536 KB

题目描述

Give you a N*N(1N2000)Square.For each grid in the square,its color is red or black.Your task is to find a largest red square.

输入格式

The first line is an integer T(1T5) indicating the case number. For each case,the first line is N,then next N lines describes the square.Ifa_ij=0,indicatinga_ijis black,if a_ij=1,indicatinga_ij is red.

输出格式

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;}

 



0 0
原创粉丝点击