思路:
只说一下这个题dp的思想吧,我们对于每一行都记录最左端未关灯的位置,和最右端未关灯的位置,那么对于左端和右端的楼梯维护一下是将本层楼灯全部关闭原路返回花的时间少,还是从右端过来时间少,对于右端也一样,然后维护一个最优解决就可以了;
坑点:在dp的时候左端被更新了会影响下面所以要记录一下初始的值.特判只有最后一行未关灯的情况
#include<iostream>
#include<cstdio>
#include<string.h>
#include<math.h>
#define inf 0x3f3f3f3f
using namespace std;
int dp[20][111];
int n,m;
int x,y;
char s[20][111];
int main()
{
x=y=-1;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%s",s[i]+1);
if(x!=-1&&y!=-1)
continue;
for(int j=1;j<=m+2;j++)
{
if(s[i][j]=='1')
{
x=i;
y=j;
break;
}
}
}
if(x==-1&&y==-1)
{
printf("0\n");
}
else
{
int l,r;
memset(dp,inf,sizeof(dp));
dp[n][1]=0;
for(int i=n;i>0;i--)
{
dp[i][1]=min(dp[i][1],dp[i+1][1]+1);
dp[i][m+2]=min(dp[i][m+2],dp[i+1][m+2]+1);
l=0,r=0;
for(int j=2;j<=m+1;j++)
{
if(s[i][j]=='1')
{
if(!l) l=j;
r=j;
}
}
int w=dp[i][1];//这个值会发生改变,要提前记录.
if(r)
dp[i][1]=min(dp[i][1]+2*(r-1),dp[i][m+2]+m+1);
if(l)
dp[i][m+2]=min(dp[i][m+2]+2*(m+2-l),w+m+1);
}
l=0,r=0;
int ans=inf;
for(int i=1;i<=m+2;i++)
{
if(s[x][i]=='1')
{
if(!l)
l=i;
r=i;
}
}
/*for(int i=n;i>=1;i--)
{
for(int j=1;j<=m+2;j++)
printf("%d %d %d\n",i,j,dp[i][j]);
}*/
ans=min(dp[x+1][1]+r,dp[x+1][m+2]+(m+2-l)+1);
if(x==n)
{
ans=r-1;
}
printf("%d\n",ans);
}
}