• 【JZOJ4930】【NOIP2017提高组模拟12.18】C


    题目描述

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

    数据范围

    对于100%的数据,n,m<=100

    =w=

    f[i][j][k][l]表示,已经牺牲掉上面的i行,下面的k行,左边的j行,以及右边的l行的最大机器人数。
    方程易推。

    代码

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const char* fin="aP3.in";
    const char* fout="aP3.out";
    const int inf=0x7fffffff;
    const int maxn=107;
    int n,m,i,j,k,l,ans,tot;
    char a[maxn][maxn];
    int sum[maxn][maxn];
    int ex,ey;
    int f[2][maxn][maxn][maxn],v;
    int getsum(int sx,int sy,int tx,int ty){
        if (sx>tx || sy>ty) return 0;
        return sum[tx][ty]-sum[sx-1][ty]-sum[tx][sy-1]+sum[sx-1][sy-1];
    }
    int main(){
        scanf("%d%d
    ",&n,&m);
        for (i=1;i<=n;i++){
            for (j=1;j<=m;j++){
                a[i][j]=getchar();
                if (a[i][j]=='o'){
                    sum[i][j]=1;
                }else if (a[i][j]=='E'){
                    ex=i;
                    ey=j;
                }
                sum[i][j]=sum[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
            }
            scanf("
    ");
        }
        v=0;
        for (i=0;i<=n;i++){
            memset(f[1-v],0,sizeof(f[1-v]));
            for (j=0;j<=m;j++)
                for (k=0;k<=n;k++)
                    for (l=0;l<=m;l++){
                        if (ex+i>n || ex-k<1 || ey+j>m || ey-l<1) continue;
                        //if (ex<i || ex>n-k || ey<j || ey>m-l) continue;
                        if (ex+i+1<=n-k) f[1-v][j][k][l]=max(f[1-v][j][k][l],f[v][j][k][l]+getsum(ex+i+1,max(j+1,ey-l),ex+i+1,min(m-l,ey+j)));
                        if (ey+j+1<=m-l) f[v][j+1][k][l]=max(f[v][j+1][k][l],f[v][j][k][l]+getsum(max(i+1,ex-k),ey+(j+1),min(n-k,ex+i),ey+(j+1)));
                        if (ex-k-1>=1+i) f[v][j][k+1][l]=max(f[v][j][k+1][l],f[v][j][k][l]+getsum(ex-(k+1),max(j+1,ey-l),ex-(k+1),min(m-l,ey+j)));
                        if (ey-l-1>=1+j) f[v][j][k][l+1]=max(f[v][j][k][l+1],f[v][j][k][l]+getsum(max(i+1,ex-k),ey-(l+1),min(n-k,ex+i),ey-(l+1)));
                        ans=max(ans,f[v][j][k][l]);
                    }
            v=1-v;
        }
        printf("%d",ans);
        return 0;
    }

    =o=

    事实上,比赛中我已经注意到,如果强制某个机器人获救的话,必然牺牲的是连续的数行或数列。
    利用这一点,就可以推出,对当前场面有影响的,就是上下左右四个方向牺牲的行列数。
    由于n,m<=100,所以加上剪枝,O(n4)的动态规划是可行的。


    可惜我当时直往搜索的方向想,结果什么都没搞成。

    这里写图片描述

    这启示说,如果找到了代表某种场面,只需要很少参数的话,就可以利用动态规划了。

  • 相关阅读:
    07 面向对象
    06 二维数组
    05 数组
    04 循环控制语句
    03控制流程语句
    Mybatis-plus
    Solr全文检索服务器
    剑指offer-序列化和反序列化二叉树-树-python
    剑指offer-顺序打印二叉树节点(系列)-树-python
    剑指offer-对称二叉树-树-python
  • 原文地址:https://www.cnblogs.com/hiweibolu/p/6714811.html
Copyright © 2020-2023  润新知