这道题也是看网上的解题报告得出的解法。。。
首先,knight接king的点不需要在整个棋盘枚举,king最多move两步。这个是能够通过所有测试点的。至于为什么这样,网上也搜到过证明,但是无心看了。
其次,floyd是个非常低效的算法,因为它确定无疑的要n^3的时间复杂度,适合于密集图(因为算法和边的个数无关),但是我们遇到的一般是稀疏图。SPFA甚至BFS都更好。之前看johnson算法似乎是适用于稀疏图的。
再次,usaco给的标程没看懂。。。
/* ID: thestor1 LANG: C++ TASK: camelot */ #include <iostream> #include <cmath> #include <cstdio> #include <cstring> #include <climits> #include <vector> #include <cassert> #include <string> #include <algorithm> #include <stack> #include <set> #include <queue> using namespace std; struct Position{ int r, c; Position() { } Position(int r, int c) { this->r = r; this->c = c; } Position(const Position& other):r(other.r), c(other.c){ } Position& operator =(const Position& other){ r=other.r; c=other.c; return *this; } }; const int MAXR = 26; const int MAXC = 30; const int MAXN = MAXR * MAXC; int dis[MAXR][MAXC][MAXR][MAXC]; const int directx[] = {-2, -1, 1, 2, 2, 1, -1, -2}; const int directy[] = {1, 2, 2, 1, -1, -2, -2, -1}; bool marked[MAXR][MAXC]; int index(int r, int c, int C) { return r * C + c; } bool isWithin(int r, int c, int R, int C) { return r >= 0 && r < R && c >= 0 && c < C; } void spfa(const Position &s, const int R, const int C) { if(marked[s.r][s.c]) { return; } marked[s.r][s.c] = true; for(int i = 0; i < R; ++i) { for(int j = 0; j < C; ++j) { dis[s.r][s.c][i][j] = INT_MAX; } } dis[s.r][s.c][s.r][s.c] = 0; deque<Position> que; bool onQueue[MAXR][MAXC]; memset(onQueue, false, MAXN * sizeof(bool)); //int s = index(r, c, C); que.push_back(s); onQueue[s.r][s.c] = true; while(!que.empty()) { /* if(que.size() == 51 && que.front().r == 24 && que.front().c == 18) { fprintf(stdout, "debug\n"); } fprintf(stdout, "que.size: %d\n", que.size()); */ Position u = que.front(); que.pop_front(); //fprintf(stdout, "u: (%d, %d)\n", u.r, u.c); if(dis[s.r][s.c][u.r][u.c] == INT_MAX) { continue; } onQueue[u.r][u.c] = false; for(int d = 0; d < 8; ++d) { int vr = u.r + directx[d]; int vc = u.c + directy[d]; if(!isWithin(vr, vc, R, C)) { continue; } Position v(vr, vc); //v.r = vr; //v.c = vc; if(dis[s.r][s.c][u.r][u.c] + 1 < dis[s.r][s.c][v.r][v.c]) { dis[s.r][s.c][v.r][v.c] = dis[s.r][s.c][u.r][u.c] + 1; if(!onQueue[v.r][v.c]) { if(que.empty() || dis[s.r][s.c][v.r][v.c] < dis[s.r][s.c][que.front().r][que.front().c]) { que.push_front(v); } else { que.push_back(v); } onQueue[v.r][v.c] = true; } } } } } int main() { FILE *fin = fopen ("camelot.in", "r"); FILE *fout = fopen ("camelot.out", "w"); //freopen("log.txt", "w", stdout); int R, C; fscanf(fin, "%d%d\n", &C, &R); //int N = R * C; memset(marked, false, R * C * sizeof(bool)); Position king; char r; fscanf(fin, "%c", &r); king.r = r - 'A'; int c; fscanf(fin, "%d\n", &c); king.c = c - 1; assert(king.r < R && king.c < C); //fprintf(stdout, "king: \n%d %d\n", king.r, king.c); vector<Position> knights; while(fscanf(fin, "%c", &r) > 0) { if(r < 'A' || r > 'Z') { continue; } Position knight; knight.r = r - 'A'; fscanf(fin, " %d", &c); knight.c = c - 1; knights.push_back(knight); } //for(int i = 0; i < knights.size(); ++i) //{ //assert(knights[i].r < R && knights[i].c < C); //fprintf(stdout, "%c %d\n", knights[i].r + 'A', knights[i].c + 1); //} //fprintf(stdout, "number of knights: %d\n", knights.size()); for(int i = 0; i < knights.size(); ++i) { spfa(knights[i], R, C); /* for(int r = 0; r < R; ++r) { for(int c = 0; c < C; ++c) { fprintf(stdout, "%d\t", dis[knights[i].r][knights[i].c][r][c]); } fprintf(stdout, "\n"); } */ } int minmoves = -1; for(int gr = 0; gr < R; ++gr)//gathering point { for(int gc = 0; gc < C; ++gc) { int knightsdis = 0; for(int i = 0; i < knights.size(); ++i) { knightsdis += dis[knights[i].r][knights[i].c][gr][gc]; } int kingmove = 0; int pr, pc; int knightsmove = 0; for(int kingmover = -2; kingmover <= 2; ++kingmover) { for(int kingmovec = -2; kingmovec <= 2; ++kingmovec) { kingmove = max(abs(kingmover), abs(kingmovec)); //if(!kingmover && !kingmovec) //{ //kingmove = 0; //} //else //{ //kingmove = 1; //} pr = king.r + kingmover; pc = king.c + kingmovec; if(!isWithin(pr, pc, R, C)) { continue; } spfa(Position(pr, pc), R, C); for(int pk = 0; pk < knights.size(); ++pk) //pickup knight { if(dis[knights[pk].r][knights[pk].c][pr][pc] == INT_MAX || dis[pr][pc][gr][gc] == INT_MAX) { continue; } knightsmove = knightsdis - dis[knights[pk].r][knights[pk].c][gr][gc] + dis[knights[pk].r][knights[pk].c][pr][pc] + dis[pr][pc][gr][gc]; int moves = knightsmove + kingmove; if(minmoves < 0 || moves < minmoves) { minmoves = moves; } } } } } } fprintf(fout, "%d\n", minmoves < 0 ? 0 : minmoves); return 0; }