UVa 1533 - Moving Pegs
Published on 2016-01-21描述
给定一个有 个格子三角形状的棋盘,除了给定的一个位置 每一个位置上都有一个棋子,你可以进行移动棋子,直到棋盘只剩下最后一个棋子在位置 ,但必须遵循如下规则:
- 你每次可以选择任意一个有棋子的格子开始移动。
- 每次移动必须沿着直线移动,必须隔至少 个格子移动(例如 不可以移动到 ,因为中间没有间隔),但只能移动到没有棋子的格子。
- 移动的过程中起始位置和途中经过的格子必须有棋子,移动完毕后,这些棋子会被消去(例如从 之后,格子 的棋子被消去,格子 有一颗棋子)。
请你输出字典序最小的移动方案。
样例输入
1 5
样例输出
10 12 5 3 8 15 12 6 13 7 9 1 7 10 8 7 9 11 14 14 5
分析
题意搞清楚之后明显不难,但我根本不知道跳棋规则,样例都炸了好半天。。。
记录每一个格子的 个移动方向移动到的格子,由于需要字典序最小,那么依此按照左上,右上,左,右,左下,右下的顺序来保证字典序最小。
用二进制位记录格子上是否有棋子,然后 BFS + 状压判重即可。 个状态完全可行。注意 BFS 扩展的时候先从标号小的开始扩展保证字典序。
细节见代码,标号从 开始。当然打表这种猥琐事情我就不干了。
代码
// Created by Sengxian on 1/21/16. // Copyright (c) 2015年 Sengxian. All rights reserved. // UVa 1533 BFS #include <algorithm> #include <iostream> #include <climits> #include <cassert> #include <cstring> #include <cstdio> #include <queue> #include <cmath> #include <vector> #define br putchar('\n') using namespace std; int dir[15][6] = <!--0-->; inline int ReadInt() { int x = 0, ch = getchar(); while(!isdigit(ch)) ch = getchar(); do { x = x * 10 + ch - '0'; ch = getchar(); }while(isdigit(ch)); return x; } const int maxn = 15; struct state { int S, cnt; int step[maxn][2]; state(): cnt(0) {} void erase(int x) {if((S >> x) & 1) S ^= 1 << x;} void add(int x) {if(!((S >> x) & 1)) S += 1 << x;} bool count(int x) {return (S >> x) & 1;} void print() { for(int i = 14; i >= 0; --i) printf("%d", (S >> i) & 1); br; } state operator = (const state &s) { S = s.S; cnt = s.cnt; memcpy(step, s.step, sizeof(s.step)); return *this; } }s; bool vis[1 << maxn]; bool Solve(int empty) { queue<state> q; memset(vis, 0, sizeof(vis)); state s; s.S = (1 << maxn) - 1; s.erase(empty); q.push(s); vis[s.S] = true; while(!q.empty()) { state now = q.front(); q.pop(); for(int u = 0; u < maxn; ++u) { if(!now.count(u)) continue; //no peg so cannot move. for(int k = 0; k < 6; ++k) { state news = now; int v = u; news.erase(u); int tot = 0; while(true) { v = dir[v][k]; tot++; if(v == -1) break; //cannot go further. if(news.count(v)) {news.erase(v); continue;} //cannot move to it since there are peg in it. if(tot == 1) break; news.add(v); if(!vis[news.S]) { vis[news.S] = true; news.cnt = now.cnt + 1; news.step[now.cnt][0] = u; news.step[now.cnt][1] = v; q.push(news); if(news.S == (1 << empty)) { printf("%d\n", news.cnt); for(int i = 0; i < news.cnt; ++i) printf("%d %d%c", news.step[i][0] + 1, news.step[i][1] + 1, i + 1 == news.cnt ? '\n' : ' '); return true; } } news.erase(v); break; } } } } return false; } int main() { int caseNum = ReadInt(); while(caseNum--) { int empty = ReadInt() - 1; if(!Solve(empty)) puts("IMPOSSIBLE"); } return 0; }
附加输入
15 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
附加输出
9 4 1 6 4 11 2 14 11 15 6 1 10 10 7 11 4 4 1 9 7 2 1 4 10 1 14 2 1 7 11 14 15 13 13 4 7 2 9 10 3 1 6 7 1 12 3 1 10 14 12 11 13 13 6 15 3 9 1 4 6 1 13 6 10 3 11 13 3 12 15 11 11 2 1 4 10 12 5 3 8 15 12 6 13 7 9 1 7 10 8 7 9 11 14 14 5 9 1 6 4 1 13 4 7 2 15 13 2 14 11 15 15 3 1 6 9 1 7 6 1 11 4 9 7 14 11 11 2 15 6 6 4 1 7 10 3 8 12 5 15 3 13 6 1 10 2 9 11 2 14 5 2 9 10 8 10 2 9 11 2 12 5 3 8 13 4 1 7 14 5 15 3 3 8 7 9 9 1 10 4 1 11 4 4 6 12 5 10 8 15 12 12 3 1 10 9 4 11 1 4 10 1 14 2 1 7 11 14 15 13 13 4 4 11 9 14 12 2 14 7 2 1 4 15 13 3 15 11 14 4 13 15 12 9 4 13 1 4 11 2 13 11 15 13 2 14 3 15 15 12 11 13 9 11 14 2 11 3 12 10 3 1 6 11 13 15 12 6 13 12 14 9 6 15 1 6 7 1 12 3 1 10 15 12 11 13 13 6 6 15