一维跳棋
一维跳棋
题目描述
一维跳棋是一种在1*(2N+1)的棋盘上玩的游戏。一共有 2N 个棋子,其中 N个是黑的,N 个是白的。游戏开始前,N 个白棋子被放在一头,N 个黑棋子被放在另一头,中间的格子空着。在这个游戏里有两种移动方法是允许的:你可以把一个棋子移到与它相邻的空格;你可以把一个棋子跳过一个(仅一个)与它不同色的棋子到达空格。
对于N = 3 的情况,棋盘状态依次为 ... (略)
对应空格所在的位置为 3 5 6 4 2 1 3 5 7 6 4 2 3 5 4
相信大家千里迢迢地找到这篇蒟蒻的题解,应该都度过题目了吧,所以题目就略写了
输入格式
(1<=N<=10),一个整数N
输出格式
依次输出空格所在棋盘的位置,每个整数间用空格分隔,每行 5 个数(每行结尾无空格,最后一行可以不满 5 个数;如果有多组移动步数最小的解,输出第一个数最小的解)
样例输入
4
样例输出
4 6 7 5 3
2 4 6 8 9
7 5 3 1 2
4 6 8 7 5
3 4 6 5
题目分析
看到最小+ N<=10联想到bfs.
这里的问题是bfs过程中的状态怎么定义,发现只有把整个棋盘存储下来才可以。
棋盘,一个空格,两个颜色,状态压缩,懂
当然了也可以用vector那样存储的就是对应的棋盘编号,其实这题明显用vector更好
蒟蒻这里用的bitset,和状态压缩思想基本一致,可是关于bitset转10进制,好像不是O(1)的,
这不废话吗
然后我就TLE+MLE了,然后发现能打表,也就不想写正解了。 (我真懒
废话结束~
用vector能避免掉很多转10进制的操作,而且交换数字也方便。
这里给出bitset的代码,讲真的状压也就枚举二进制集合方便 (可能是我太菜了
#include <bits/stdc++.h>
using namespace std;
// 1 -> W || 0-> B / E
int n;
const int d[] = { 2,1,-1,-2 };
struct __status {
bitset<22> s;
int epos;
bool operator==(const __status& rhs) const {
return rhs.s == s && epos == rhs.epos;
}
};
bool vis[1 << 22][21];
__status p[1 << 22][21]; // 状 压 要 素
__status build_st() {
__status a;
for (int i = n + 1; i < 2 * n + 1; ++i) {
a.s[i] = 1;
}
a.epos = n;
return a;
}
__status build_ed() {
__status a;
for (int i = 0; i < n; ++i) {
a.s[i] = 1;
}
a.epos = n;
return a;
}
__status st, ed;
vector<int> ans;
void gen_ans(__status t) {
if (t == st) return;
gen_ans(p[t.s.to_ulong()][t.epos]);
ans.push_back(2 * n - t.epos + 1);
}
inline void sswap(bitset<22>& src, const int& i, const int& j) {
bool t = src[i];
src[i] = src[j];
src[j] = t;
}
inline bool check(const int& pos) {
return pos >= 0 && pos <= 2 * n;
}
void bfs() {
st = build_st(), ed = build_ed();
vis[st.s.to_ulong()][st.epos] = 0;
queue<__status> q;
q.push(st);
while (!q.empty()) {
__status cur = q.front();
if (cur == ed) {
gen_ans(ed);
return;
}
q.pop();
for (int i = 0; i < 4; ++i) {
if (check(cur.epos + d[i]) == 0) continue;
bitset<22> m = cur.s;
int epos = cur.epos;
sswap(m, epos, epos + d[i]);
int val = m.to_ulong();
if (vis[val][epos + d[i]] == 0) {
vis[val][epos + d[i]] = 1;
p[val][epos + d[i]] = cur;
q.push({ m,epos + d[i] });
}
} //这一段代码里也就这个奇技淫巧能勉强学学了。
}
}
void clear() {
memset(vis, 0, sizeof(vis));
memset(p, 0, sizeof(p));
vector<int>().swap(ans);
}
int main() {
freopen("ans.out","w",stdout);
while (1) {
clear();
scanf("%d", &n);
bfs();
int tag = 0;
for (int i = 0; i < ans.size(); ++i) {
printf("%d ,", ans[i]);
++tag;
if (tag == 5) {
tag = 0;
puts("");
}
}
printf("\n\n\n");
}
}
改正解5分钟足矣! (当然不是打表
等我有空了会更一个十进制和一个vector正解。 要去肝作业了,还要中考。
心情凌乱的时候写的,轻喷。

浙公网安备 33010602011771号