Problem B. Safe Squares Google APAC 2017 University Test Round C

这一题居然是DP,打死我也看不出来==

maxsq[i][j]表示以[i,j]为右下端点的最大safe square的边长,其中square属于[0,0]..[i,0]..[i,j]..[0,j]范围内。

如果[i,j]有monster,那么以[i,j]为端点的safe square不存在,maxsq[i][j]=0

如果[i,j]有monster,那么最大safe square的边长由三个相邻点[i][j-1],[i-1][j],[i-1][j-1]的最短边长决定,因为max safe square要保证是个连通区域。这个性质举几个例子画个图就能看出来。

对于每个max safe square,在max safe square内以[i][j]结尾的safe square的个数就是边长。因为每个[i][j]对应的safe square个数是disjoint的,直接相加即为最后结果。

#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>

using namespace std;

//2017 RoundC Problem B. Safe Squares
int T;
int R;
int C;
int K;
const int maxn=3010;
int mp[maxn][maxn];
int maxsq[maxn][maxn];
int main()
{
    freopen("B-large-practice.in","r",stdin);
    freopen("output.txt","w",stdout);
    scanf("%d", &T);
    for(int ca=1;ca<=T;ca++)
    {
        scanf("%d %d %d",&R,&C,&K);
        memset(mp,0,sizeof(mp));
        memset(maxsq,0,sizeof(maxsq));
        for(int i=0;i<K;i++)
        {
            int ri;
            int ci;
            scanf("%d %d",&ri,&ci);
            mp[ri][ci]=1;
        }
        for(int i=0;i<R;i++)
        {
            maxsq[i][0]=(mp[i][0]==0?1:0);
        }
        for(int j=0;j<C;j++)
        {
            maxsq[0][j]=(mp[0][j]==0?1:0);
        }
        for(int i=1;i<R;i++)
        {
            for(int j=1;j<C;j++)
            {
                if(mp[i][j]==0)
                {
                    int tmp=min(maxsq[i-1][j],maxsq[i-1][j-1]);
                    tmp=min(tmp,maxsq[i][j-1]);
                    maxsq[i][j]=tmp+1;
                }
                else
                {
                    maxsq[i][j]=0;
                }
            }
        }
        long long ans=0;
        for(int i=0;i<R;i++)
        {
            for(int j=0;j<C;j++)
            {
                //cout<<maxsq[i][j]<<" ";
                ans+=maxsq[i][j];
            }
            //cout<<endl;
        }
        printf("Case #%d: %lld\n",ca,ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值