Codeforece 812 B 动态规划

题意:

有一栋大楼n层,每层有m个房间,左右两边还有楼梯间。

Staff 想去把整个大楼的等关掉,问他需要多少时间能做完。

起始位置 左下角。

问题分析:

仔细看一下其实我们可以把除了亮灯的最高层以为每一层都分割成两个状态。

一个是最后停留在左边的楼梯间d(Layer, 0);

一个是最后停留在右边的楼梯间d(Layer, 1);

仔细思考一下从 x层到x+1层的时候我们只需要判断四个状态:

//left 该层停留在左边点的最小时间 right 右边

//Node.l   该层最左边的灯 Node.r该层最右边的灯  

1. x . left ->(x+1).left ->(x+1).right

2.x.right ->(x+1).rigth->(x+1).left

3.x.left->(x+1).left ->(x+1).Node.l->(x+1).left

4.x.right->(x+1).right ->(x+1).Node.r->(x+1).right

由四个状态推得

d(x+1,left) = min((1),(4));

d(x+1.,right)=min((2),(3));


#include<bits/stdc++.h>
using namespace std;
#define N 1005
int d[N][2];
char M[N][N];
struct Node{
    int l=0,r=0;
    int p;
}L[N],R[N];
 int n,m;
 int v[N];
void Cal(int i){
    L[i].l=L[i].p;
    R[i].l=R[i].p;
    L[i].r=m-1-L[i].p;
    R[i].r=m-1-R[i].p;
}
int main()
{
    scanf("%d%d",&n,&m);
    m+=2;
    memset(v,0,sizeof(v));
    int Layer=-1;
    for(int i=0;i<n;i++){
        scanf("%s",M[i]);
        L[i].p=0;
        R[i].p=n;
        for(int j=0;j<m;j++){
            if(M[i][j]=='1'){
                if(!L[i].p)L[i].p=j;
                R[i].p=j;
                if(Layer==-1)
                Layer=i;
                v[i]=1;
            }
        }
        Cal(i);
    }
    d[n][0]=-1;
    d[n][1]=m-1;
    if(Layer==-1){
        cout<<"0"<<endl;
        return 0;
    }
    for(int i=n-1;i>Layer;i--){
        if(!v[i]){
            d[i][0]=d[i+1][0]+1;
            d[i][1]=d[i+1][1]+1;
            continue;
        }
        d[i][0]=min(d[i+1][1]+m-1,d[i+1][0]+2*R[i].l)+1;
        d[i][1]=min(d[i+1][0]+m-1,d[i+1][1]+2*L[i].r)+1;
     }

    printf("%d\n",1+min(d[Layer+1][0]+R[Layer].l,d[Layer+1][1]+L[Layer].r));
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值