思路原本n * n的表格不能很好的同时维护点和边的合法情况
所以扩展到2n * 2n这样点和点之间的边我们也能判断是否合法了
1|2|
3|4| 这里是2*2的表格,一共4个点
扩展其中x就是边的位置,数字则是上述的原本位置。
(一共4*4个点,右侧和下测的一些无用x点省略了)
1|x|2|
x|x|x|
3|x|4|
1->2从(1,1)到(1, 3)经过了边(1, 2)
1->4从(1,1)到(3, 3)经过了边(2, 2)
从规律中可以看出从a(x,y)到b(x2,y2)经过的边为(x+px, y+py)
其中px py为偏移量。px = (x2 - x) / 2
至此特殊处理完成。剩下的就是拙劣的写法了
#include <bits/stdc++.h>
using namespace std;
string ans = "99999999999";
const int N = 100;
int a[N][N];
bool st[N][N];//点
bool e[N][N];//边
int n, m, nn;
int isok = 0;
int dx[8] = {-2, -2, 0, 2, 2, 2, 0, -2};
int dy[8] = {0, 2, 2, 2, 0, -2, -2, -2};
void dfs(int x, int y, string &s, int c){
// cout<<s<<'\n';
st[x][y] = true;
if(isok){//剪枝,字典序来检查是否还有搜下去的必要,对于相同位置s>ans则return
if(s.back() > ans[s.size() - 1]){
st[x][y] = false;
return;
}
}
if(x == nn - 1 && y == nn - 1){//走到了最后一个点
if(c == n * n - 1){
ans = min(ans, s);
isok = 1;
}
st[nn - 1][nn - 1] = false;
return;
}
for(int i = 0 ; i < 8 ; i ++){
int xx = x + dx[i], yy = y + dy[i];
if(xx < 1 || xx >= nn || yy < 1 || yy >= nn)continue;
int px = xx - x , py = yy - y;
px /= 2;
py /= 2;
if(!st[xx][yy] && !e[x + px][y + py] && (a[x][y] + 1) % m == a[xx][yy]){
s.push_back(i + '0');
e[x + px][y + py] = true;
dfs(xx, yy, s, c + 1);
s.pop_back();
e[x + px][y + py] = false;
}
}
st[x][y] = false;
}
int main(){
cin>>n>>m;
nn = n * 2;
for(int i = 1 ; i < nn ; i += 2)
for(int j = 1 ; j < nn ; j += 2)
cin>>a[i][j];
string t = "";
dfs(1, 1, t, 0);
if(ans == "99999999999"){
cout<<-1<<'\n';
}else cout<<ans<<'\n';
return 0;
}