题意:
给定N*M,N<=100,M<=15的0、1矩阵。每次可以改变上下左右等5个的值。
求最少几次可以把所有的值变为1.
解法:
枚举第一行的操作情况,从2-n行便确定了。这里因为M<=15,用位运算表示比较方便。
求X里二进制表示1的个数,用到了一种分治法。详见matrix67的文章
#include<stdio.h>
#include<string.h>
#include<math.h>
#define inf 100000000
int n,m;
int all;
int g[110];
int d[110];
int getlen(int x) //求x二进制表示里1的个数
{
x=(x&0x55555555)+((x>>1)&0x55555555);
x=(x&0x33333333)+((x>>2)&0x33333333);
x=(x&0x0f0f0f0f)+((x>>4)&0x0f0f0f0f);
x=(x&0x00ff00ff)+((x>>8)&0x00ff00ff);
x=(x&0x0000ffff)+((x>>16)&0x0000ffff);
return x;
}
int main()
{
while (scanf("%d%d",&n,&m)==2)
{
memset(g,0,sizeof(g));
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
{
int tmp;
scanf("%d",&tmp);
g[i]=g[i]<<1 | tmp;
}
}
int all = (1<<m)-1;
int ans = inf;
for (int i=0;i<=all;i++)
{
for (int j=1;j<=n;j++)
d[j]=g[j];
int cnt = getlen(i);
d[1] ^= i; //自己
d[1] ^=i>>1; //右边
d[1] ^= i<<1;//左边
d[1] &= all; //清除多余的数
d[2] ^= i;
for (int j=2;j<=n;j++)
{
int t = d[j-1]^all;
d[j] ^=t;
d[j] ^=t>>1;
d[j]^=t<<1;
d[j] &=all;
d[j+1] ^=t;
cnt += getlen(t);
}
if (d[n]==all)
ans = ans<cnt?ans:cnt;
}
if (ans==inf)
printf("no solution\n");
else
printf("%d\n",ans);
}
return 0;
}