Sagheer, the Hausmeister CodeForces - 812B (简单dp)

46 篇文章 0 订阅
38 篇文章 0 订阅

Some people leave the lights at their workplaces on when they leave that is a waste of resources. As a hausmeister of DHBW, Sagheer waits till all students and professors leave the university building, then goes and turns all the lights off.

The building consists of n floors with stairs at the left and the right sides. Each floor has m rooms on the same line with a corridor that connects the left and right stairs passing by all the rooms. In other words, the building can be represented as a rectangle with n rows and m + 2 columns, where the first and the last columns represent the stairs, and the m columns in the middle represent rooms.

Sagheer is standing at the ground floor at the left stairs. He wants to turn all the lights off in such a way that he will not go upstairs until all lights in the floor he is standing at are off. Of course, Sagheer must visit a room to turn the light there off. It takes one minute for Sagheer to go to the next floor using stairs or to move from the current room/stairs to a neighboring room/stairs on the same floor. It takes no time for him to switch the light off in the room he is currently standing in. Help Sagheer find the minimum total time to turn off all the lights.

Note that Sagheer does not have to go back to his starting position, and he does not have to visit rooms where the light is already switched off.

Input
The first line contains two integers n and m (1 ≤ n ≤ 15 and 1 ≤ m ≤ 100) — the number of floors and the number of rooms in each floor, respectively.

The next n lines contains the building description. Each line contains a binary string of length m + 2 representing a floor (the left stairs, then m rooms, then the right stairs) where 0 indicates that the light is off and 1 indicates that the light is on. The floors are listed from top to bottom, so that the last line represents the ground floor.

The first and last characters of each string represent the left and the right stairs, respectively, so they are always 0.

Output
Print a single integer — the minimum total time needed to turn off all the lights.

Example

Input
2 2
0010
0100
Output
5

Input
3 4
001000
000010
000010
Output
12

Input
4 3
01110
01110
01110
01110
Output
18

Note
In the first example, Sagheer will go to room 1 in the ground floor, then he will go to room 2 in the second floor using the left or right stairs.

In the second example, he will go to the fourth room in the ground floor, use right stairs, go to the fourth room in the second floor, use right stairs again, then go to the second room in the last floor.

In the third example, he will walk through the whole corridor alternating between the left and right stairs at each floor.

大致题意:有n层楼,每一层有m个房间和两个楼梯分别在最左边和最右边,你可以任意选一个楼梯上楼。告诉你没个房间的灯的亮暗信息,你需要把所有亮着的灯都关掉。每次移动或者上楼都需要花费一个单位时间。关灯不需要花费时间,需要你经过那个房间即可。开始你在最底层的最左边,问你关掉所有灯所需的最少时间。

思路:想要花费最少时间,肯定是一层一层的关掉灯,然后往上走,又因为关灯不需要花费时间,所以我们记录下每一层灯的最左边位置和最右边位置。然后达到每一层都有两种可能,要么从左边上楼,要么从右边上楼。假设dp[i][0]表示第i层楼,从左边上楼时的最少花费,dp[i][1]表示从右边上楼时的最少花费。状态转移方程也就很好列了,具体看下面代码。

代码如下

#include <iostream> 
#include <cmath>
#include <algorithm>
#include <cstring>
#include <queue>
#include <cstdio>
#include <map>
using namespace std; 
#define ll long long int 
const int INF=0x3f3f3f3f;  
int n ;
int l[20],r[20],vis[20];
int dp[20][2];
int main()  
{    
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(l,0,sizeof(l));
        memset(r,0,sizeof(r));
        memset(vis,0,sizeof(vis));
        for(int i=n;i>=1;i--)
        {
            char s[200];
            scanf("%s",s);
            for(int j=1;j<=m;j++)
                if(s[j]=='1')
                {
                    l[i]=j;
                    vis[i]=1;//记录第i层是否有没关的灯
                    break;
                }

            for(int j=m;j>=1;j--)
                if(s[j]=='1')
                {
                    r[i]=j;
                    break;
                }
        }

        while(!vis[n]&&n>=0)
        {
            n--;
        }
        if(n==1)//如果只有第一层有灯开着
        {
            printf("%d\n",r[1]);
            continue;
        }
        if(n==-1)//如果没有灯开着
        {
            printf("0\n");
            continue;
        }
        memset(dp,INF,sizeof(dp));
        dp[1][0]=2*r[1];//左边上楼
        dp[1][1]=m+1;//右边上楼

        for(int i=2;i<n;i++)
        {
            if(!vis[i])//如果当前层没有灯开着
            {
                dp[i][0]=dp[i-1][0]+1;
                dp[i][1]=dp[i-1][1]+1;
                continue;
            }
            dp[i][0]=min(dp[i-1][0]+2*r[i]+1,dp[i-1][1]+m+2);//从左边上去
            dp[i][1]=min(dp[i-1][1]+2*m-2*l[i]+3,dp[i-1][0]+m+2);//从右边上去            
        }
        printf("%d\n",min(dp[n-1][0]+r[n]+1,dp[n-1][1]+m-l[n]+1+1));
    }
}  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值