这道题做的让自己很惭愧
一开始想不出来思路,后来只好放弃看题解却发现如此简单。就是把问题拆解为三个部分,king让谁接,在哪里接,重点设置在哪,枚举即可
预处理就是floyd算出所有节点之间距离
可是预处理的时候犯了一个很严重的错误,因为把整个棋盘为了转化为一个图,就把每个格子2维坐标降维改成一字排开,计算下一步移动当时也就改成在一维增量,例如(-2, -1)就对应转化为\(-2*64-1\)。但是在判断下一步能否还在棋盘内的时候,必须要还原到二维。比如正好在边界,然后跳到一个本该出界的位置,但是按照这种计算下一步的方法,下一步还是在棋盘64个节点里面,本质原因就是同一个数有两种表示方法,而我这种下一步处理,没有办法保证这个数是由一个惟一坐标得出的
提交时还WA了好几次,改了下读取输入发现过来,有时候真是玄学
#include <iostream> #include <algorithm> #include <queue> #include <string> #include <vector> #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <stack> #include <map> #include <set> using namespace std; const int maxn= 66; const int V= 64; const int INF= 0x3f3f3f3f; const int width= 8; int ndv[maxn][maxn], kdv[maxn][maxn]; int nt_step[8][2]= {{-2, -1}, {-2, 1}, {-1, -2}, {-1, 2}, {1, -2}, {1, 2}, {2, -1}, {2, 1}}; int kg_step[8][2]= {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}; int p[maxn]; string s; void Init() { for (int i= 0; i< V; ++i){ for (int j= i+1; j< V; ++j){ kdv[i][j]= kdv[j][i]= INF; ndv[i][j]= ndv[j][i]= INF; } kdv[i][i]= ndv[i][i]= 0; } for (int i= 0; i< V; ++i){ int nx, ny, kx, ky; for (int j= 0; j< 8; ++j){ ky= (i>>3)+kg_step[j][0]; kx= (i&7)+kg_step[j][1]; ny= (i>>3)+nt_step[j][0]; nx= (i&7)+nt_step[j][1]; if (nx>= 0 && nx < width && ny>= 0 && ny< width){ ndv[i][(ny<<3)+nx]= 1; } if (kx>= 0 && kx < width && ky>= 0 && ky< width){ kdv[i][(ky<<3)+kx]= 1; } } } // floyd for (int k= 0; k< V; ++k){ for (int i= 0; i< V; ++i){ for (int j= 0; j< V; ++j){ ndv[i][j]= min(ndv[i][j], ndv[i][k]+ndv[k][j]); kdv[i][j]= min(kdv[i][j], kdv[i][k]+kdv[k][j]); } } } } int main() { Init(); cin>>s; int sz= s.size(); int x, y, tot= 0; for (int i= 0; i< sz; i+= 2){ x= s[i]-'A'; y= s[i+1]-'1'; p[tot++]= (y<<3)+x; } int ans= tot == 0 ? 0 : INF; for (int dst= 0; dst< V; ++dst){ for (int wt= 0; wt< V; ++wt){ int tmp= kdv[p[0]][wt]+ndv[wt][dst]; for (int q= 1; q< tot; ++q){ tmp+= ndv[p[q]][dst]; } for (int k= 1; k< tot; ++k){ ans= min(ans, tmp-ndv[p[k]][dst]+ndv[p[k]][wt]); } } } printf("%d\n", ans); return 0; }