题目描述 守护着神秘宝藏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
Give Me A BOOM please
Case
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;
}
|