有一个n * n 的矩阵,不重不漏地随机放着 1到 n*n 的每个数。现在你站在数字1的位置,每次可以有三种走法:
问最少花费多少精力值可以走完n^2个点。精力最小的时候要求切换走法次数也最少。
输出最小精力和最少切换走法次数。
bfs搜索,状态可以这么设定dp[i][j][z][t][k]表示到达g[i][j]这个点,用的是第z种走法,已经换了t次走法,已经按顺序访问了k个点,此时的最小精力值。
转移分为两种:
#include
#define ms(a,b) memset(a,b,sizeof(a))
#define ll long long
#define PII pair
#define sz(x) (int)(x.size())
using namespace std;
const int INF = 0x3f3f3f3f;
struct node{
int x,y,z,t,k;
node(int _x,int _y,int _z,int _t,int _k) {
x = _x;
y = _y;
z = _z; //当前方式
t = _t; //换了多少次
k = _k; //经过前k个点
}
};
int n;
int g[15][15];
int dp[11][11][3][201][101]; //0是日,1是直,2是斜线
int dx1[8][2] = {{-2,-1},{-2,1},{2,-1},{2,1},{-1,-2},{-1,2},{1,-2},{1,2}}; //日
int dx2[4][2] = {{-1,0},{1,0},{0,1},{0,-1}}; //直线
int dx3[4][2] = {{-1,-1},{-1,1},{1,-1},{1,1}}; //斜线
int sx,sy,tx,ty;
void bfs(int sx,int sy){
memset(dp,-1,sizeof dp);
dp[sx][sy][0][0][1] = dp[sx][sy][1][0][1] = dp[sx][sy][2][0][1] = 0;
queue q;
q.push(node(sx,sy,0,0,1));
q.push(node(sx,sy,1,0,1));
q.push(node(sx,sy,2,0,1));
while(!q.empty()){
node nd = q.front();q.pop();
int x = nd.x, y = nd.y, z = nd.z, t = nd.t , k = nd.k;
//原地换走法
for(int i=0;i<3;i++){
if(i==z) continue;
if(dp[x][y][i][t+1][k]!=-1) continue;
dp[x][y][i][t+1][k] = dp[x][y][z][t][k]+1;
q.push(node(x,y,i,t+1,k));
}
//不换状态继续走
if(z==0) {
for(int i=0;i<8;i++){
int xx = x+dx1[i][0], yy = y + dx1[i][1],kk = k;
if(xx<1 || xx>n || yy<1 || yy>n) continue;
if(g[xx][yy] == k+1) kk++;
if(dp[xx][yy][z][t][kk]!=-1) continue;
dp[xx][yy][z][t][kk] = dp[x][y][z][t][k]+1;
q.push(node(xx,yy,z,t,kk));
}
}
if(z==1) {
for(int j=1;j<=10;j++){
for(int i=0;i<4;i++){
int xx = x+j*dx2[i][0], yy = y + j*dx2[i][1],kk = k;
if(xx<1 || xx>n || yy<1 || yy>n) continue;
if(g[xx][yy] == k+1) kk++;
if(dp[xx][yy][z][t][kk]!=-1) continue;
dp[xx][yy][z][t][kk] = dp[x][y][z][t][k]+1;
q.push(node(xx,yy,z,t,kk));
}
}
}
if(z==2) {
for(int j=1;j<=10;j++){
for(int i=0;i<4;i++){
int xx = x+j*dx3[i][0], yy = y + j*dx3[i][1],kk = k;
if(xx<1 || xx>n || yy<1 || yy>n) continue;
if(g[xx][yy] == k+1) kk++;
if(dp[xx][yy][z][t][kk]!=-1) continue;
dp[xx][yy][z][t][kk] = dp[x][y][z][t][k]+1;
q.push(node(xx,yy,z,t,kk));
}
}
}
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++) {
cin>>g[i][j];
if(g[i][j]==1) {
sx = i;
sy = j;
}
if(g[i][j] == n*n){
tx = i;
ty = j;
}
}
}
bfs(sx,sy);
int ans = INF;
for(int z=0;z<3;z++){ //当前方式
for(int t=0;t<201;t++){ //换了多少次
if(dp[tx][ty][z][t][n*n]!=-1){
ans = min(dp[tx][ty][z][t][n*n],ans);
}
}
}
int ok=0;
for(int t=0;t<201;t++){
for(int z=0;z<3;z++){
if(dp[tx][ty][z][t][n*n] == ans){
cout << ans << " " << t << endl;
ok = 1; break;
}
}
if(ok) break;
}
return 0;
}