钓鱼

Description

小A最近又新买了一幢别墅,里面有一个特别特别大的矩形水池,他买了很多很多鱼养在水池里。这样就可以每天都吃上水煮鱼或者酸菜鱼,以实现他最大腰围的目标!

这天小A请全体ACM班的同学到他家吃饭,其实也是为了表演一下他高超的钓鱼技术!为了表现他的超级牛力,小A钓鱼时,只会选择钓连续地排在一个正方形的一条对角线上的鱼,并且其所在的正方形内,没有别的地方还有漏“钩”之鱼。小A一次最多能钓起多少条鱼?

Input

输入包含多组测试数据。对于每组测试数据,第一行两个整数h,b(1<=h,b<=1000)表示水池的高度和宽度。之后h行,每行b个字符Cij。’*’表示该位置有鱼,’.’表示该位置没有鱼。

Output

对于每组测试数据,输出一行包含一个整数,表示小A一次最多能钓起多少条鱼。

Sample Input

2 3
*.*
.**
4 5
*....
.*...
.....
...*.

Sample Output

2
2

HINT


取水池左上角两行两列的左上到右下的对角线。

*.


.*

共能钓起2条鱼。

题意:求最大的单位矩阵!

思路:将所有对角线上的*个数计算好,将所有所有矩阵中的*个数也计算好,然后用二分查找进行搜索,成立条件:对角线上*的个数 == 它所在矩阵中*的个数 == 二分查找的个数。

这道题是网上某大神A了教我的,膜拜。。。

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define init(x) memset(x,0,sizeof(x))
#define judge(x) (((x) == '*') ? 1 : 0)
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b))
int h,b;
char str[1005][1005];
int sum[1005][1005];
int diagonalLift[1005][1005],diagonalRight[1005][1005];
int find(int k)//遍历寻找最大单位矩阵
{
    int i,j,n = h-k+1,m = b-k+1;
    for(i=0;i<n;i++)
        for(j=0;j<m;j++)
        {
            if(diagonalLift[i+k][j+k] - diagonalLift[i][j] == k &&       sum[i+k][j+k] - sum[i+k][j] - sum[i][j+k] + sum[i][j] == k) return 1;//当左对角线上的*数与整个矩阵中的*数相等时即为单位矩阵
            if(diagonalRight[i+k][j+1] - diagonalRight[i][j+k+1] == k && sum[i+k][j+k] - sum[i+k][j] - sum[i][j+k] + sum[i][j] == k) return 1;//同上,只不过是右对角线
        }
return 0;}
int twopart()//将MIN(h,b)为终点进行二分查找最大单位矩阵,因为最大的单位矩阵也只能到达h,b中小的一个
{
    int ans = 0,mid,head = 1,tail = MIN(h,b);
    while(head <= tail)
    {
        mid = (head + tail) / 2;
        if(find(mid))
        {
            ans = MAX(ans,mid);
            head = mid + 1;
        }
        else
            tail = mid - 1;
    }
return ans;}
int main()
{
    int i,j;
    while(scanf("%d%d",&h,&b)!=EOF)
    {
        init(sum);init(diagonalLift);init(diagonalRight);
        for(i=0;i<h;i++)
            scanf("%s",str[i]);
        for(i=1;i<=h;i++)
        {
            for(j=1;j<=b;j++)
            {
                diagonalLift[i][j] = diagonalLift[i-1][j-1] + judge(str[i-1][j-1]);//计算从1,1到i,j所有左对角线上*的个数
                diagonalRight[i][j] = diagonalRight[i-1][j+1] + judge(str[i-1][j-1]);//同理计算右对角线
                sum[i][j] = judge(str[i-1][j-1]) + sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1];//同理计算所有矩阵上*的个数
            }
        }
        //for(i=1;i<=h;i++){for(j=1;j<=b;j++)printf("%d ",diagonalLift[i][j]);printf("\n");}
        //for(i=1;i<=h;i++){for(j=1;j<=b;j++)printf("%d ",diagonalRight[i][j]);printf("\n");}
        //for(i=1;i<=h;i++){for(j=1;j<=b;j++)printf("%d ",sum[i][j]);printf("\n");}
        printf("%d\n",twopart());
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值