很久没有1A了~爽~
题目也是很常规的状态压缩题目,这类题目一般都是预处理所有状态,然后通过枚举,判断是否符合要求,再从符合要求的末状态中找到答案即可。
这个题目,由于给定的是所有偶数列,那么,可以想到,每一列只跟左右两列有关,其他列对其没有影响。因此,只需要确定了两列中的一列的状态,另外一列便可以枚举状态判断是否符合题意。从左至右,枚举第一列的所有状态,第二列是数字列,枚举第三列状态,符合题意就记录。依次类推,从末状态中得到最终解即可。
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int n,m;
int map[15][15];
int status[2100];
int dp[15][2100];
int getnum(int i)
{
int s=0;
while (i>0)
{
if (i&1)
s++;
i>>=1;
}
return s;
}
int getss(int i,int t)
{
if (t==0)
return 0;
int s=(1<<t);
s=(s&i);
if (s>0)
s=1;
else
s=0;
return s;
}
int main()
{
while (cin>>n>>m)
{
for (int i=1;i<=n;i++)
for (int t=1;t<=m;t++)
cin>>map[i][t];
memset(dp,-1,sizeof(dp));
int cnt=(1<<(n+1));
for (int i=0;i<cnt;i++)
{
int s=0;
dp[0][i]=getnum(i);
}
for (int i=1;i<=m;i++)
{
for (int t=0;t<cnt;t++)
{
if (dp[i-1][t]==-1)
continue ;
for (int k=0;k<cnt;k++)
{
int p=1;
for (int j=1;j<=n;j++)
{
int s=getss(t,j-1)+getss(t,j)+getss(t,j+1)+getss(k,j-1)+getss(k,j)+getss(k,j+1);
if (s!=map[j][i])
{
p=0;
break;
}
//cout<<j<<" "<<i<<" "<<map[j][i]<<" "<<s<<" "<<t<<" "<<k<<endl;
}
if (p)
{
//cout<<i<<" "<<t<<" "<<k<<endl;
if (dp[i][k]==-1)
dp[i][k]=dp[i-1][t]+getnum(k);
else
dp[i][k]=min(dp[i][k],dp[i-1][t]+getnum(k));
}
}
}
}
int ans=0x3f3f3f3f;
for (int i=0;i<cnt;i++)
{
if (dp[m][i]!=-1)
ans=min(ans,dp[m][i]);
}
cout<<ans<<endl;
}
}