看起来就很难的一道题
本题存在一个小陷阱,它看起来像是单回路模型(毕竟是求路径),然而它其实是多回路模型,或者说可以用多回路模型做。
这道题求的是最短距离,那么这就意味着如果出现了多出来的一个回路,那么它就会因为带来了额外的距离而被舍去。
于是乎,我们就可以用多回路也就是Eat the trees的思路来转移,但是路径分为2和3两种,所以轮廓线上的状态也有0,2,3三种,用四进制表示即可。
细节很多,要小心。
代码如下:
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <map>
#define chkmin(x,y) x=min(x,y);
using namespace std;
int n,m,d[2][60000],H[60000],s,a[20][20],IH[1<<20];
void getHash(int k,int x)
{
if(k==m+1)
{
IH[x]=s;
H[s++]=x;
return;
}
getHash(k+1,x<<2);
getHash(k+1,x<<2|2);
getHash(k+1,x<<2|3);
}
int dp()
{
memset(d,0x3f,sizeof(d));
d[1][0]=0;
for(register int i=1,cur=1;i<=n;i++,cur^=1)
{
for(register int j=0;j<m;j++,cur^=1)
{
memset(d[cur^1],0x3f,sizeof(d[cur^1]));
for(int k=0;k<s;k++)
{
register int temp=d[cur][k],t=H[k],x=t>>(j<<1)&3,y=t>>((j+1)<<1)&3;
if(temp>1000)continue;
if(a[i][j]==0)
{
if(x==y)
{
if(x)
{
chkmin(d[cur^1][IH[t^(x<<(j<<1))^(y<<((j+1)<<1))]],temp+1);
}
else
{
chkmin(d[cur^1][IH[t^(10<<(j<<1))]],temp+1);
chkmin(d[cur^1][IH[t^(15<<(j<<1))]],temp+1);
chkmin(d[cur^1][k],temp);
}
}
if(x+y==2||x+y==3)
{
chkmin(d[cur^1][k],temp+1);
chkmin(d[cur^1][IH[t^((x|y)<<(j<<1))^((x|y)<<((j+1)<<1))]],temp+1);
}
}
else if(a[i][j]==1)
{
if(x==0&&y==0)
{
chkmin(d[cur^1][k],temp);
}
}
else
{
if(x==0&&y==0)
{
chkmin(d[cur^1][IH[t^(a[i][j]<<(j<<1))]],temp+1);
chkmin(d[cur^1][IH[t^(a[i][j]<<((j+1)<<1))]],temp+1);
}
if(x+y==a[i][j])
{
chkmin(d[cur^1][IH[t^(x<<(j<<1))^(y<<((j+1)<<1))]],temp+1);
}
}
}
}
memset(d[cur^1],0x3f,sizeof(d[cur^1]));
for(int j=0;H[j]<(1<<(m<<1));j++)
{
if(d[cur][j]>1000)continue;
chkmin(d[cur^1][IH[H[j]<<2]],d[cur][j]);
}
}
return (d[n*(m+1)%2][0]>1000)?0:d[n*(m+1)%2][0]-2;
}
int main()
{
while(cin>>n>>m)
{
if(n==0)break;
memset(H,0,sizeof(H));
s=0;
memset(IH,0,sizeof(IH));
for(int i=1;i<=n;i++)
{
for(int j=0;j<m;j++)
{
cin>>a[i][j];
}
}
getHash(0,0);
cout<<dp()<<endl;
}
return 0;
}