Cipher Lock

Cipher Lock

Accepted : 23Submit : 76
Time Limit : 2500 MSMemory Limit : 65536 KB 
题目描述

守护着神秘宝藏One Piece的是一把非常神秘的密码锁,这个密码锁有n排滚轮,每个滚轮有m个格子,刻着0,1两种数字。作为一把神秘的密码锁,开锁的方式却非常的简单,只要向左或向右转动滚轮使某一列的数字全是1就可以了。(向左滚动:所有的数字向左移动一位,最左边的数字移动到最右边,如001100左滚动一次变为011000,向右滚动与向左滚动操作相同,只是方向相反),作为即将成为海贼王的你,一定会选择最帅气的开锁方式———既用最少的次数来打开守护着神秘宝藏One Piece的密码锁。那么,请问最帅气的开锁次数需要转动密码锁几次呢?

输入

有多组数据输入,每个数据第一行为两个整数n,m表示有n排密码锁,每个密码锁有m个格子,其中(1≤n≤100,1≤m≤10 4 )。接下来的有n行输入,表示每排密码锁的初始状态。

输出

对每组数据输出两行,第一行输出“Case # :”表示当前是几号样例(从1开始编号),第二行,如果可以开锁就输出一个整数表示最少需要移动几次,否则输出“Give Me A BOOM please”。(均不用输出“”号)

样例输入
2 3
111
000
3 6
101010
000100
100000
样例输出
Case #1:
Give Me A BOOM please
Case #2:
3
预处理出所有位置到最近1的距离,然后枚举每一列
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

int n,m,g[110][33000],dis[110][33000];
const int INF=0x3f3f3f3f;

int main()
{
  ///freopen("input.txt","r",stdin);
  ///freopen("output.txt","w",stdout);
  int cas=1;
while(scanf("%d%d",&n,&m)!=EOF)
{
  memset(dis,63,sizeof(dis));
  getchar();
  int B1=m,B2=2*m,B3=3*m;
  for(int i=0;i<n;i++)
  {
    bool flag=false;
    for(int j=0;j<m;j++)
    {
      char c;
      scanf("%c",&c);
      g[i][j]=(c=='1')?1:0;
      g[i][j+B1]=g[i][j+B2]=g[i][j];
      if(g[i][j]==1) dis[i][j+B1]=0;
    }
    getchar();
  }
  ///left_distance
  for(int i=0;i<n;i++)
  {
    bool flag=false;
    int dist=0;
    for(int k=B1-1;k>=0;k--)
    {
      dist++;
      if(g[i][k]==1) {flag=true; break;}
    }
    if(flag==false) continue;
    dis[i][B1]=min(dis[i][B1],dist);
    for(int j=B1+1;j<B2;j++)
    {
      if(dis[i][j]==0) continue;
      else dis[i][j]=dis[i][j-1]+1;
    }
  }
  ///right_distance
  for(int i=0;i<n;i++)
  {
    bool flag=false;
    int dist=0;
    for(int k=B2;k<B3;k++)
    {
      dist++;
      if(g[i][k]==1) {flag=true; break;}
    }
    if(flag==false) continue;
    dis[i][B2-1]=min(dis[i][B2-1],dist);
    for(int j=B2-2;j>=B1;j--)
    {
      if(dis[i][j]==0) continue;
      else dis[i][j]=min(dis[i][j],dis[i][j+1]+1);
    }
  }
  int ans=INF;
  for(int i=B1;i<B2;i++)
  {
    int temp=0;
    bool flag=true;
    for(int j=0;j<n;j++)
    {
      if(dis[j][i]==INF)
      {
        flag=false; break;
      }
      temp+=dis[j][i];
    }
    if(flag) ans=min(ans,temp);
    else { ans=INF; break; }
  }
  printf("Case #%d:\n",cas++);
  if(ans>=INF) puts("Give Me A BOOM please");
  else printf("%d\n",ans);
}
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值