zoukankan      html  css  js  c++  java
  • 瑰丽华尔兹

    【题目描述】

    舞厅是一个N行M列的矩阵,矩阵中的某些方格上堆放了一些家具,其他的则是空地。钢琴可以在空地上滑动,但不能撞上家具或滑出舞厅。每个时刻,钢琴都会随着船体倾斜的方向向相邻的方格滑动一格,相邻的方格可以是向东、向西、向南或向北的。而艾米丽可以选择施魔法或不施魔法:如果不施魔法,则钢琴会滑动;如果施魔法,则钢琴会原地不动。艾米丽知道每段时间的船体的倾斜情况。她想使钢琴在舞厅里滑行的路程尽量长,希望你能帮助她。

    【输入描述】

    第一行包含5个数:N、M、x、y和K。N和M描述舞厅的大小,x和y为钢琴的初始位置,我们对船体倾斜情况是按时间的区间来描述的,且从1开始计算时间,比如“在[1,3]时间里向东倾斜,[4,5]时间里向北倾斜”,因此这里的K表示区间的数目。以下N行,每行M个字符,描述舞厅里的家具。第i行第j列的字符若为‘.’,则表示该位置是空地;若为‘x’,则表示有家具。以下K行,顺序描述K个时间区间,格式为:s[i]、t[i]、d[i](1 ≤ i ≤ K)。表示在时间区间[s[i],t[i]]内,船体都是向d[i]方向倾斜的。d[i]为1、2、3、4中的一个,依次表示北、南、西、东(分别对应矩阵中的上、下、左、右)。输入保证区间是连续的,即:

    s[1]=1

    t[i]=s[i-1]+1(1 < i ≤ K)

    t[K]=T

    【输出描述】

    输出文件仅有1行,包含一个整数,表示钢琴滑行的最长距离(即格子数)。

    【样例输入】

    4 5 4 1 3

    ..xx.

    .....

    ...x.

    .....

    1 3 4

    4 5 1

    6 7 2

    【样例输出】

    6

    【数据范围及提示】

    50%的数据中,1 ≤ N,M ≤ 200,T ≤ 200;
    100%的数据中,1 ≤ N,M≤ 200,K ≤ 200,T ≤ 40000。

    源代码:
    
    #include<cstdio>
    #include<algorithm>
    #define INF 1000000000
    using namespace std;
    char S[201][201];
    int DP[201][201][201];
    int x[4]={-1,1,0,0},y[4]={0,0,-1,1}; //由于要对应方向,所以是有顺序的。
    int Q[201],Pos[201];
    int N,M,X,Y,K,Head,Tail,ans;
    void Push(int Now,int T,int T1,int T2)
    {
        if (T==-INF) //这个点连到都没到过。
          return;
        while (T-Now>Q[Tail]&&Head<=Tail) //入队前先删除队尾,队尾不够优,就删除。即新入队的元素的可更新距离大于队尾的。
          Tail--;
        Q[++Tail]=T-Now;
        Pos[Tail]=Now;
    }
    void Solve(int Num,int T1,int T2,int D,int T) //Num表示当前区间编号,T表示此区间内最多能移动的长度。
    {
        Head=1;
        Tail=0;
        int Now=1;
        while (T1<=N&&T1>=1&&T2<=M&&T2>=1)
        {
            if (S[T1][T2]=='x') //一旦有了障碍物,之前的点都用不到了。
            {
                Head=1;
                Tail=0;
            }
            else
              Push(Now,DP[Num-1][T1][T2],T1,T2); //尝试入队。
            while (Now-Pos[Head]>T&&Head<=Tail)
              Head++; //利用区间长度删除过长的队头,队头储存着这一列(行)距离最远的点。
            if (Head<=Tail) //更新DP数组。
              DP[Num][T1][T2]=Q[Head]+Now;
            else
              DP[Num][T1][T2]=-INF;
            ans=max(ans,DP[Num][T1][T2]);
            T1+=x[D];
            T2+=y[D]; //按顺序,沿着此列(行)更新下一点。
            Now++; //更新距离长度。
        }
    }
    int main()
    {
        scanf("%d%d%d%d%d",&N,&M,&X,&Y,&K);
        for (int a=1;a<=N;a++) //怎么都用字符串读入。
          scanf("%s",S[a]+1);
        for (int a=1;a<=N;a++)
          for (int b=1;b<=M;b++)
            DP[0][a][b]=-INF; //赋最小值。
        DP[0][X][Y]=0;
        for (int a=1;a<=K;a++)
        {
            int T1,T2,T;
            scanf("%d%d%d",&T1,&T2,&T);
            if (T==1) //上。
              for (int b=1;b<=M;b++)
                Solve(a,N,b,T-1,T2-T1+1);
            if (T==2) //下。
              for (int b=1;b<=M;b++)
                Solve(a,1,b,T-1,T2-T1+1);
            if (T==3) //左。
              for (int b=1;b<=N;b++)
                Solve(a,b,M,T-1,T2-T1+1);
            if (T==4) //右。
              for (int b=1;b<=N;b++)
                Solve(a,b,1,T-1,T2-T1+1);
        }
        printf("%d",ans);
        return 0;
    }
    
    /*
        设DP[k][i][j]表示第k个区间时,(X,Y)到达(i,j)的最多步数,L为区间长度也为此区间内最多移动步数。
        状态转移方程(以向下为例):
            DP[k][i][j]=max(DP[k-1][T][j])+(i-T),(i-L <= T <= i)
        一列(行)一列(行)地进行DP,则如果中途有障碍物,那么之前便无用了。
        一个点的DP值可以随纵纵横横的处理转移到其他任意的点,所以正确。
    */
  • 相关阅读:
    线段树优化建图 && CF-786B.Legacy(优化建图,dijkstra)
    构建高性能JavaScript应用
    关于互联网应用前端架构的一些思考
    Router模块
    View模块
    Backbone源码解析系列
    Model模块
    Events模块
    Backbone源码风格
    jQuery选择器总结
  • 原文地址:https://www.cnblogs.com/Ackermann/p/5707440.html
Copyright © 2011-2022 走看看