本题有个很好的性质,就是到不了和为奇数的点,因为每次移动要么+2要么-2要么为0 QAQ
有了这个性质,我们就知道一条边最多变化一次.这样就不用考虑后效性了.
然后我们用点权做bfs,把点权为x的进行扩展,点权为x+1的放置.
由于一个点可能被多次扩展,可能被同一点权的不同点扩展所产生2种不同代价且后者小于前者,所以我们要取min.
已经扩展的点不需要第二次扩展,我们直接标记就好了,
include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pi;
const int N=505;
char an[N][N];
int val[N][N],n,m;//每个点的最小代价
bool st[N][N];//看是否每个点用过
int d[4][2]={{-1,-1},{-1,1},{1,-1},{1,1}};
int mi[4][2]={{-1,-1},{-1,0},{0,-1},{0,0}};
char ck[]="\\//\\";
int bfs()
{
memset(val,0x3f,sizeof val);
memset(st,false,sizeof st);
deque<pi>q;
val[1][1]=0;
q.push_front({1,1});
while(q.size())
{
auto temp=q.front();
q.pop_front();
int x=temp.first;int y=temp.second;
if(st[x][y]) continue;
st[x][y]=true;
for(int i=0;i<4;i++)
{
int a=x+d[i][0];int b=y+d[i][1];
if(a<1||a>n+1||b<1||b>m+1) continue;
int ca=x+mi[i][0],cb=y+mi[i][1];
int z=val[x][y]+(an[ca][cb]!=ck[i]);
if(z<val[a][b])
{
val[a][b]=z;
if(an[ca][cb]==ck[i]) q.push_front({a,b});
else q.push_back({a,b});
}
}
}
return val[n+1][m+1];
}
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>an[i][j];
}
}
if((n+m)&1) puts("NO SOLUTION");
else cout<<bfs()<<endl;
}
return 0;
}
京公网安备 11010502036488号