题意:
有一栋大楼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));
}