UVa 1601
类似“推箱子”,将n个小写字母推到对应的大写字母的位置。每一步对每个小写字母可推最多一次,且不可发生冲突。
将“局势”看做状态,就是一道隐式图搜索,但是状态数比较多,时间上还是挺紧的。
由于有>1/4的格子都是障碍物,可以将可走的格子抽出单独建图,邻接表存储,再广搜即可。
在此基础上可以将算法改进为双向广搜,这样速度更快(实测快了有一倍)。
双向广搜有个坑,就是要正反向每次扩展一层(而不是一个节点),否侧会漏解。
为了防止退化,可以按照正向和反向的节点数量决定下一层扩展正向or反向(实测确实更快了)。
#include
#include
#include
#include
#include
#include
using namespace std;
char g[20][20];
int w, h, n, st[3], ed[3], cnt, idx[20][20], locate[1<<8], dx[4] = { 1, -1, 0, 0 }, dy[4] = { 0, 0, 1, -1 };
const int inf = 1e9 + 7;
vector<int> to[20 * 20];
void init()
{
for(int i = 0; i < h; i++) gets(g[i]);
cnt = 0;
for(int i = 0, k = 0; i < h; i++)
for(int j = 0; j < w; j++)
if(g[i][j] != '#') {
idx[i][j] = ++cnt;
to[cnt].clear(); to[cnt].push_back(cnt);
if(isupper(g[i][j])) {
locate[g[i][j]] = k++;
}
}
for(int i = 0; i < h; i++)
for(int j = 0; j < w; j++)
if(g[i][j] != '#') {
if(isupper(g[i][j])) {
ed[locate[g[i][j]]] = idx[i][j];
}
if(islower(g[i][j])) {
st[locate[toupper(g[i][j])]] = idx[i][j];
}
for(int k = 0, a, b; k < 4; k++) {
a = i + dx[k], b = j + dy[k];
if(a >= 0 && a < h && b >= 0 && b < w && g[a][b] != '#')
to[idx[i][j]].push_back(idx[a][b]);
}
}
to[cnt + 1].clear(); to[cnt + 1].push_back(cnt + 1);
to[cnt + 2].clear(); to[cnt + 2].push_back(cnt + 2);
if(n == 1) { st[1] = ++cnt; ed[1] = st[1]; st[2] = ++cnt; ed[2] = st[2]; }
if(n == 2) { st[2] = ++cnt; ed[2] = st[2]; }
}
struct Node {
int v[3], d;
Node(int a, int b, int c, int _d) { v[0] = a, v[1] = b, v[2] = c; d = _d; }
};
queue que[2];
int dis[2][1<<8][1<<8][1<<8], num[2];
bool check(int a, int b, int c, int i, int j, int k)
{
if(a == b || b == c || c == a) return false;
if(b == i && a == j || b == k && c == j || c == i && a == k) return false;
return true;
}
int bfs()
{
int ans = inf;
memset(dis, -1, sizeof(dis));
while(!que[0].empty()) que[0].pop(); num[0] = 1;
while(!que[1].empty()) que[1].pop(); num[1] = 1;
que[0].push(Node(st[0], st[1], st[2], 0)); dis[0][st[0]][st[1]][st[2]] = 0;
que[1].push(Node(ed[0], ed[1], ed[2], 0)); dis[1][ed[0]][ed[1]][ed[2]] = 0;
while(!que[0].empty() && !que[1].empty()) {
int x = int(num[0] > num[1]), y = int(num[0] <= num[1]);
int dep = que[x].front().d;
while(!que[x].empty() && que[x].front().d == dep)
{
Node now = que[x].front(); que[x].pop();
if(dis[y][now.v[0]][now.v[1]][now.v[2]] >= 0) {
return now.d + dis[y][now.v[0]][now.v[1]][now.v[2]];
}
for(int i = 0, a; i < to[now.v[0]].size(); i++) {
a = to[now.v[0]][i];
for(int j = 0, b; j < to[now.v[1]].size(); j++) {
b = to[now.v[1]][j];
for(int k = 0, c; k < to[now.v[2]].size(); k++) {
c = to[now.v[2]][k];
if(check(a, b, c, now.v[0], now.v[1], now.v[2]) && dis[x][a][b][c] < 0)
{
dis[x][a][b][c] = now.d + 1;
que[x].push(Node(a, b, c, now.d + 1)); num[x]++;
}
}
}
}
}
}
return -1;
}
int main()
{
//freopen("in.txt", "r", stdin);
while(cin >> w >> h >> n)
{
if(w + h + n == 0) break;
while(getchar() != '\n') continue;
init();
cout << bfs() << endl;
}
return 0;
}