网址如下:
The Morning after Halloween - UVA 1601 - Virtual Judge (vjudge.net)
感觉自己和废物一样,除了用bfs啥都不会,顶多改改其中的细节
代码如下:
#include<cstdio>
#include<vector>
#include<cstring>
#include<cctype>
#include<queue>
using namespace std;const int maxwh = 16;
const int maxn = 3;
const int x[5]{-1, 1, 0, 0, 0};//上下左右停
const int y[5]{0, 0, -1, 1, 0};struct Node{int g_x[maxn], g_y[maxn], dist;Node():dist(0){memset(g_x, 0, sizeof(g_x)); memset(g_y, 0, sizeof(g_y));}
};vector<int> G[maxwh][maxwh];
char map[maxwh][maxwh];
int w, h, n, ans;
int vis[maxwh][maxwh][maxwh][maxwh][maxwh][maxwh];
int t_x[maxn], t_y[maxn];
queue<Node> q;
Node v;void init(void){memset(vis, 0, sizeof(vis));memset(t_x, 0, sizeof(t_x));memset(t_y, 0, sizeof(t_y));
}
void update_G(void){for(int i = 0; i < h; i++){for(int j = 0; j < w; j++){G[i][j].clear();if(map[i][j] != '#'){G[i][j].push_back(4);for(int m = 0; m < 4; m++){int _x = i + x[m], _y = j + y[m];if(_x >= 0 && _y >= 0 && _x < h && _y < w && map[_x][_y] != '#') G[i][j].push_back(m);}}}}
}
bool is_arrived(Node &u){for(int i = 0; i < n; i++)if(u.g_x[i] != t_x[i] || u.g_y[i] != t_y[i]) return false;return true;
}
void move(Node &u, int i){if(i == maxn){v.dist = u.dist + 1;bool is = true;//判断是否占用同一位置for(int i = 0; i < n; i++)for(int j = i + 1; j < n; j++)if(is && v.g_x[i] == v.g_x[j] && v.g_y[i] == v.g_y[j]) is = false;//判断是否交换位置for(int i = 0; i < n; i++)for(int j = i + 1; j < n; j++)if(is && v.g_x[i] == u.g_x[j] && v.g_y[i] == u.g_y[j] && v.g_x[j] == u.g_x[i] && v.g_y[j] == u.g_y[i]) is = false;if(is) q.push(v);return;}if(i >= n){v.g_x[i] = v.g_y[i] = 0; move(u, i + 1);}else{vector<int> &tmp = G[u.g_x[i]][u.g_y[i]];for(auto it = tmp.begin(); it != tmp.end(); it++){v.g_x[i] = u.g_x[i] + x[*it];v.g_y[i] = u.g_y[i] + y[*it];move(u, i + 1);}}
}
void bfs(void){while(!q.empty()){Node u = q.front(); q.pop();if(vis[u.g_x[0]][u.g_y[0]][u.g_x[1]][u.g_y[1]][u.g_x[2]][u.g_y[2]] && u.dist > vis[u.g_x[0]][u.g_y[0]][u.g_x[1]][u.g_y[1]][u.g_x[2]][u.g_y[2]]) continue;vis[u.g_x[0]][u.g_y[0]][u.g_x[1]][u.g_y[1]][u.g_x[2]][u.g_y[2]] = u.dist;if(is_arrived(u)){ans = u.dist; break;}//移动move(u, 0);}while(!q.empty()) q.pop();
}int main(void)
{while(scanf("%d%d%d", &w, &h, &n) == 3 && w){getchar(); init();//输入地图Node tmp;for(int i = 0; i < h; i++){for(int j = 0; j < w; j++){char c = getchar(); map[i][j] = c;if(isupper(c)){t_x[c - 'A'] = i; t_y[c - 'A'] = j;}else if(islower(c)){tmp.g_x[c - 'a'] = i; tmp.g_y[c - 'a'] = j;}}getchar();}update_G();//更新空格图q.push(tmp);bfs();printf("%d\n",ans);}return 0;
}
这题比较炸裂的一点在于,移动的点可以高达3个,一次可以延申出来的状态有5*5*5 = 125个
纵使题目表明有很多障碍,可以延申出来的状态也是很多
同时,我已经根据给出的地图重新建立了一个图(就是那个G数组)来记录该点合法的移动方向,但是最后还是超时了
但是状态的记录倒是没多大问题,因为地图很小,纵使使用占用内存最大的哈希表也不会让内存爆炸
说是可以换一个算法,比如双向广度优先搜索,但是我感觉这玩意对效率的提升并没有什么帮助(话虽如此,我也还没有尝试)