一维跳棋

一维跳棋

题目描述

一维跳棋是一种在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正解。 要去肝作业了,还要中考

心情凌乱的时候写的,轻喷。

posted @ 2021-02-12 22:41  周昂没有周昂  阅读(226)  评论(0)    收藏  举报