Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #define DONE 1147797409030816545
- #include <sstream>
- #include <iostream>
- #include <queue>
- #include <unordered_set>
- using namespace std;
- const unsigned long long Masks[] = {
- 0x000000000000000F,
- 0x00000000000000F0,
- 0x0000000000000F00,
- 0x000000000000F000,
- 0x00000000000F0000,
- 0x0000000000F00000,
- 0x000000000F000000,
- 0x00000000F0000000,
- 0x0000000F00000000,
- 0x000000F000000000,
- 0x00000F0000000000,
- 0x0000F00000000000,
- 0x000F000000000000,
- 0x00F0000000000000,
- 0x0F00000000000000,
- 0xF000000000000000,
- };
- const unsigned long long AntiMasks[] = {
- 0xFFFFFFFFFFFFFFF0,
- 0xFFFFFFFFFFFFFF0F,
- 0xFFFFFFFFFFFFF0FF,
- 0xFFFFFFFFFFFF0FFF,
- 0xFFFFFFFFFFF0FFFF,
- 0xFFFFFFFFFF0FFFFF,
- 0xFFFFFFFFF0FFFFFF,
- 0xFFFFFFFF0FFFFFFF,
- 0xFFFFFFF0FFFFFFFF,
- 0xFFFFFF0FFFFFFFFF,
- 0xFFFFF0FFFFFFFFFF,
- 0xFFFF0FFFFFFFFFFF,
- 0xFFF0FFFFFFFFFFFF,
- 0xFF0FFFFFFFFFFFFF,
- 0xF0FFFFFFFFFFFFFF,
- 0x0FFFFFFFFFFFFFFF
- };
- //Состояние
- struct Puzzle {
- unsigned long long data; // sequence
- string Prev; // Prev;
- int Dist;
- int ZeroPos;
- Puzzle(string P);
- void setAt(int place, unsigned char value);
- unsigned char getAt(int place) const;
- void Distance();
- };
- Puzzle::Puzzle(string P) : Prev(P), Dist(0), ZeroPos(0) {}
- void Puzzle::setAt(int place, unsigned char value) {
- data = (data & AntiMasks[place]) | (static_cast<long long>( value ) << (place << 2));
- }
- unsigned char Puzzle::getAt(int place) const {
- return static_cast<unsigned char>((data & Masks[place]) >> (place << 2));
- }
- void Puzzle::Distance() {
- Dist = 0;
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- int value = getAt(4 * i + j);
- if (value != 0) {
- int targetX = (value - 1) / 4;
- int targetY = (value - 1) % 4;
- int dx = i - targetX;
- int dy = j - targetY;
- Dist += abs(dx) + abs(dy);
- }
- }
- }
- }
- bool Compare(Puzzle first, Puzzle second) {
- return first.Dist > second.Dist;
- }
- Puzzle MoveRight(const Puzzle& old) {
- Puzzle result(old.Prev + 'L');
- result.data = old.data;
- int pos = old.ZeroPos;
- unsigned char k = old.getAt(pos + 1);
- result.setAt(pos, k);
- result.setAt(pos + 1, 0);
- result.ZeroPos = pos + 1;
- return result;
- }
- Puzzle MoveLeft(const Puzzle& old) {
- Puzzle result(old.Prev + 'R');
- result.data = old.data;
- int pos = old.ZeroPos;
- unsigned char k = old.getAt(pos - 1);
- result.setAt(pos, k);
- result.setAt(pos - 1, 0);
- result.ZeroPos = pos - 1;
- return result;
- }
- Puzzle MoveUp(const Puzzle& old) {
- Puzzle result(old.Prev + 'D');
- result.data = old.data;
- int pos = old.ZeroPos;
- unsigned char k = old.getAt(pos - 4);
- result.setAt(pos, k);
- result.setAt(pos - 4, 0);
- result.ZeroPos = pos - 4;
- return result;
- }
- Puzzle MoveDown(const Puzzle& old) {
- Puzzle result(old.Prev + 'U');
- result.data = old.data;
- int pos = old.ZeroPos;
- unsigned char k = old.getAt(pos + 4);
- result.setAt(pos, k);
- result.setAt(pos + 4, 0);
- result.ZeroPos = pos + 4;
- return result;
- }
- //Решается ли
- bool IsSolved(const Puzzle& node) {
- int mistakes = node.ZeroPos / 4 + 1; //Переменная для подсчета счетности
- for (int i = 0; i < 16; i++) {
- for (int j = i + 1; j < 16; j++) {
- const int f1 = i / 4;
- const int f2 = i % 4;
- const int s1 = j / 4;
- const int s2 = j % 4;
- int first = node.getAt(f1 * 4 + f2);
- int second = node.getAt(s1 * 4 + s2);
- if (first != 0 && second != 0) {
- if (first > second) {
- mistakes++;
- }
- }
- }
- }
- if (mistakes % 2 != 0) {
- return false;
- }
- return true;
- }
- //А*
- string AStar(Puzzle start) {
- unordered_set<unsigned long long> S;
- priority_queue<Puzzle, vector<Puzzle>, bool (*)(Puzzle, Puzzle)> q(Compare); //Приоритетная очередь с сравнием для вывода минимального
- start.Distance();
- q.push(start);
- while (!q.empty()) {
- Puzzle tmp = q.top();
- q.pop();
- if (tmp.data == DONE) {
- return tmp.Prev;
- }
- S.insert(tmp.data);
- int pos = tmp.ZeroPos;
- if (pos >= 4) {
- Puzzle toPush = MoveUp(tmp);
- auto find = S.find(toPush.data);
- if (find == S.end()) {
- q.push(toPush);
- }
- }
- if (pos <= 11) {
- Puzzle toPush = MoveDown(tmp);
- auto find = S.find(toPush.data);
- if (find == S.end()) {
- q.push(toPush);
- }
- }
- if (pos % 4 != 3) {
- Puzzle toPush = MoveRight(tmp);
- auto find = S.find(toPush.data);
- if (find == S.end()) {
- q.push(toPush);
- }
- }
- if (pos % 4 != 0) {
- Puzzle toPush = MoveLeft(tmp);
- auto find = S.find(toPush.data);
- if (find == S.end()) {
- q.push(toPush);
- }
- }
- }
- }
- int main() {
- //Оптимизация ввода
- ios_base::sync_with_stdio(false);
- cin.tie(NULL);
- //Считываем начальное состояние
- Puzzle start("");
- int ZeroPos = 0;
- for (int i = 0; i < 16; i++) {
- int Input = 0;
- scanf("%i", &Input);
- start.setAt(i, static_cast<unsigned char>(Input));
- if (Input == 0) {
- ZeroPos = i;
- }
- }
- start.ZeroPos = ZeroPos;
- //Проверяем есть ли решение
- bool WillGo = IsSolved(start);
- if (!WillGo) { //Если нет решения
- cout << "-1";
- return 0;
- }
- //Иначе запускаем A*
- string answer = AStar(start);
- cout << answer.size();
- cout << "\n";
- cout << answer;
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement