C 【NOIP2017提高组模拟12.18】

22 篇文章 0 订阅
8 篇文章 0 订阅

Description

给出一个H的行和W列的网格。第i行第j列的状态是由一个字母的A[i][j]表示,如下:
“.” 此格为空。
“o” 此格包含一个机器人。
“E” 此格包含一个出口,保证出口在整个网格中有且只有一个
每次可以选择上,下,左,右之一的方向,将所有剩余的机器人向这个方向移动一个格子,如果一个机器人被移出了网格,那么这个机器人会爆炸,并立即消失。如果一个机器人移动到出口所在的格子,机器人将获救,并消失,最多有多少机器人获救。

Input

第一行两个整数n,m
接下来一个n*m的字符矩阵,共n行,每行m个字符,每个字符之间无空格,字符意义如题所示。

Output

输出一个整数,即最大的获救的机器人的数量

Sample Input

【样例输入1】
3 3
o.o
.Eo
ooo
【样例输入2】
3 4
o…
o…
oooE

Sample Output

【样例输出1】
3
【样例输出2】
5

Data Constraint

对于20%的数据,n*m<=9
对于另外40%的数据,出口在网格图的最左上角,即第1行第1列。
对于100%的数据,n,m<=100

Hint

移动序列为左,上,右时,第2行第3个与第3行第2,3个机器人获救,其他机器人爆炸


解法

dp。
我们可以知道,如果我们牺牲掉最左边一列,那么出口右边的一列就能够加入答案。那么四个方向上的是同理。
设f[l][r][u][d]表示左边牺牲l列,右边r列,上面u行,下面d行能够获得的最大数量。转移明显了。

发现空间会炸,可以开滚动。
懒得人直接用小一点的数据类型
然而我因为数组没开够调了两天QwQ.


代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(short i=a;i<=b;i++)

using namespace std;

const short maxn=105;
short f[maxn][maxn][maxn][maxn],H[maxn][maxn],L[maxn][maxn],map[maxn][maxn],n,m,x,y,ans;
char ch;

short max(short x,short y)
{
    if (x>y) return x; else return y;
}
short min(short x,short y)
{
    if (x<y) return y; else return x;
}
int main()
{
//  freopen("T.in","r",stdin); 
//  freopen("T.out","w",stdout);
    cin>>n>>m;
    ch=getchar();
    fo(i,1,n){
        while(ch!='o'&&ch!='.'&&ch!='E') ch=getchar();
        short j=1;
        while (ch=='o'||ch=='.'||ch=='E'){
            if (ch=='o') map[i][j]=1;
            else if (ch=='E') x=i,y=j;
            ch=getchar();
            ++j;
        }
    }
    fo(i,1,n)
        fo(j,1,m) H[i][j]=H[i][j-1]+map[i][j];
    fo(i,1,m)
        fo(j,1,n) L[i][j]=L[i][j-1]+map[j][i];
    memset(f,128,sizeof(f));
    f[0][0][0][0]=0;
    fo(l,0,m-y)
        fo(r,0,y-1)
            fo(u,0,n-x)
                fo(d,0,x-1)
                if (f[l][r][u][d]>=0)
                {
                    if (y+l+1<=m-r){
                        f[l+1][r][u][d]=max(f[l+1][r][u][d],
                            f[l][r][u][d]+L[y+l+1][min(x+u,n-d)]-L[y+l+1][max(x-d-1,u)]);
                        ans=max(ans,f[l+1][r][u][d]);
                    }

                    if (y-r-1>l){
                        f[l][r+1][u][d]=max(f[l][r+1][u][d],
                            f[l][r][u][d]+L[y-r-1][min(x+u,n-d)]-L[y-r-1][max(x-d-1,u)]);
                        ans=max(ans,f[l][r+1][u][d]);
                    }   

                    if (x+u+1<=n-d){
                        f[l][r][u+1][d]=max(f[l][r][u+1][d],
                            f[l][r][u][d]+H[x+u+1][min(y+l,m-r)]-H[x+u+1][max(y-r-1,l)]);
                        ans=max(ans,f[l][r][u+1][d]);
                    }           
                    if (x-d-1>u){
                        f[l][r][u][d+1]=max(f[l][r][u][d+1],
                            f[l][r][u][d]+H[x-d-1][min(y+l,m-r)]-H[x-d-1][max(y-r-1,l)]);
                        ans=max(ans,f[l][r][u][d+1]);
                    }   
                }
    printf("%d",ans);
}

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值