HDU 1401 题解
Solitaire
题目大意
每个棋子可以跳向上下左右四个方向的格子
如果格子上有棋子,可以跳过该棋子(最多跳一个)
并且保证不跳出边界
给出两个状态,每个状态包含四个棋子的坐标
问4步之内能否从第一个状态到达第二一个状态
Time: 1000 ms
Memory: 32768 kB
解题思路及分析
对每个棋子四个方向进行bfs
由于过程是可逆的,故可以进行双向搜索
访问标记每个状态时,可以把状态的4个坐标转成一个8位数来标记
原来unordered_map自定义键值类型需要自己写哈希函数……算了,转8位数标记一样的
AC代码
//#include <bits/stdc++.h>
#include <cstdio>
#include <queue>
#include <unordered_map>
#include <algorithm>
#include <cstring>
using namespace std;
struct Pos
{
int x, y;
};
struct State
{
Pos pos[4];
int step;
};
bool cmp(Pos a, Pos b)
{
return (a.x == b.x) ? (a.y < b.y) : (a.x < b.x);
}
// unordered_map<State, bool> vis1, vis2;
unordered_map<int, bool> vis1, vis2;
int mp[10][10];
int dx[] = { 1, 0, -1, 0 };
int dy[] = { 0, 1, 0, -1 };
bool ans;
bool judge(int x, int y) // 判断是否在边界内
{
return (1 <= x && x <= 8 && 1 <= y && y <= 8);
}
int to_num(State now) // 转成8位数
{
int res = 0;
for (int i = 0; i < 4; i++)
{
res = res * 100 + now.pos[i].x * 10 + now.pos[i].y;
}
return res;
}
bool bfs(State s1, State s2)
{
queue<State> q1, q2;
State now, next;
s1.step = 0;
s2.step = 0;
q1.push(s1);
q2.push(s2);
vis1[to_num(s1)] = true;
vis2[to_num(s2)] = true;
while ((!q1.empty()) || (!q2.empty()))
{
if (!q1.empty())
{
now = q1.front();
q1.pop();
memset(mp, 0, sizeof(mp));
for (int k = 0; k < 4; k++)
{
mp[now.pos[k].x][now.pos[k].y] = 1;
}
if (now.step == 4)
{
continue;
}
if (vis2[to_num(now)])
{
return true;
}
for (int i = 0; i < 4; i++) // 枚举棋子
{
for (int j = 0; j < 4; j++) // 枚举几个方向
{
next = now;
next.pos[i].x = next.pos[i].x + dx[j];
next.pos[i].y = next.pos[i].y + dy[j];
next.step = now.step + 1;
if (!judge(next.pos[i].x, next.pos[i].y))
{
continue;
}
if (mp[next.pos[i].x][next.pos[i].y] == 1) // 是否需要跳过棋子
{
next.pos[i].x = next.pos[i].x + dx[j];
next.pos[i].y = next.pos[i].y + dy[j];
}
if (!judge(next.pos[i].x, next.pos[i].y))
{
continue;
}
sort(next.pos, next.pos + 4, cmp);
int goal = to_num(next);
if (vis2[goal])
{
return true;
}
if (!vis1[goal])
{
vis1[goal] = true;
q1.push(next);
}
}
}
}
if (!q2.empty())
{
now = q2.front();
q2.pop();
memset(mp, 0, sizeof(mp));
for (int k = 0; k < 4; k++)
{
mp[now.pos[k].x][now.pos[k].y] = 1;
}
if (now.step == 4)
{
continue;
}
if (vis1[to_num(now)])
{
return true;
}
for (int i = 0; i < 4; i++) // 枚举棋子
{
for (int j = 0; j < 4; j++) // 枚举几个方向
{
next = now;
next.pos[i].x = next.pos[i].x + dx[j];
next.pos[i].y = next.pos[i].y + dy[j];
next.step = now.step + 1;
if (!judge(next.pos[i].x, next.pos[i].y))
{
continue;
}
if (mp[next.pos[i].x][next.pos[i].y] == 1) // 是否需要跳过棋子
{
next.pos[i].x = next.pos[i].x + dx[j];
next.pos[i].y = next.pos[i].y + dy[j];
}
if (!judge(next.pos[i].x, next.pos[i].y))
{
continue;
}
sort(next.pos, next.pos + 4, cmp);
int goal = to_num(next);
if (vis1[goal])
{
return true;
}
if (!vis2[goal])
{
vis2[goal] = true;
q2.push(next);
}
}
}
}
}
return false;
}
int main()
{
State start, last;
while (~scanf("%d%d", &start.pos[0].x, &start.pos[0].y))
{
vis1.clear();
vis2.clear();
for (int i = 1; i < 4; i++)
{
scanf("%d%d", &start.pos[i].x, &start.pos[i].y);
}
for (int i = 0; i < 4; i++)
{
scanf("%d%d", &last.pos[i].x, &last.pos[i].y);
}
// 每次排好序,否则可能会出现重复遍历
sort(start.pos, start.pos + 4, cmp);
sort(last.pos, last.pos + 4, cmp);
ans = bfs(start, last);
printf(ans ? "YES\n" : "NO\n");
}
return 0;
}