预处理每一层最左侧的1的位置,以及最右侧的1的位置。
f(i,0)表示第i层,从左侧上来的最小值。f(i,1)表示从右侧上来。
转移方程请看代码。
#include<cstdio> #include<algorithm> using namespace std; int n,m,left[20],right[20],f[20][2]; char a[20][110]; int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;++i){ scanf("%s",a[i]+1); } for(int i=1;i<=n;++i){ left[i]=m+2; right[i]=1; for(int j=1;j<=m;++j){ if(a[i][j+1]=='1'){ left[i]=j+1; break; } } for(int j=m;j>=1;--j){ if(a[i][j+1]=='1'){ right[i]=j+1; break; } } } f[n][1]=m+1; for(int i=n-1;i>=0;--i){ f[i][0]=min(f[i+1][0]+(right[i+1]-1)*2+1,f[i+1][1]+m+2); f[i][1]=min(f[i+1][1]+(m+2-left[i+1])*2+1,f[i+1][0]+m+2); } int nn=n+1; left[nn]=m+2; right[nn]=1; for(int i=n;i>=1;--i){ if(right[i]!=1){ nn=i; } } printf("%d ",min(f[nn][0]+right[nn]-1,f[nn][1]+m+2-left[nn])); return 0; }