每一行都可以将其循环挪位一下,问最少挪动多少下,能够使得某一列都是1.
思路:
①我们预处理出L【i】【j】表示第i行从位子j到最左边,距离j点最近的那个1的位子。
同理有R【i】【j】;
②然后我们再预处理出LL【i】表示第i行最左边的1的位子。
同理有RR【i】;
③那么我们O(m)枚举一列,表示最终这一列都是1,然后我们贪心的判断一下哪个1走过来最优即可。
过程维护一下。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
char a[150][15000];
int L[150][15000];
int R[150][15000];
int LL[150];
int RR[150];
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
memset(LL,-1,sizeof(LL));
memset(RR,-1,sizeof(RR));
memset(L,-1,sizeof(L));
memset(R,-1,sizeof(R));
for(int i=1;i<=n;i++)scanf("%s",a[i]+1);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(LL[i]==-1&&a[i][j]=='1')LL[i]=j;
if(a[i][j]=='1')L[i][j]=j;
else L[i][j]=L[i][j-1];
}
}
for(int i=1;i<=n;i++)
{
for(int j=m;j>=1;j--)
{
if(RR[i]==-1&&a[i][j]=='1')RR[i]=j;
if(a[i][j]=='1')R[i][j]=j;
else R[i][j]=R[i][j+1];
}
}
int output=0x3f3f3f3f;
for(int i=1;i<=m;i++)
{
int sum=0;
for(int j=1;j<=n;j++)
{
int A=15000000;
int B=15000000;
if(L[j][i]!=-1)A=i-L[j][i];
if(R[j][i]!=-1)B=R[j][i]-i;
int C=15000000;
int D=15000000;
if(LL[j]!=-1)C=LL[j]+m-i;
if(RR[j]!=-1)D=m-RR[j]+i;
sum+=min(min(A,B),min(C,D));
}
output=min(output,sum);
}
if(output>=15000000)printf("-1\n");
else printf("%d\n",output);
}
}