[USACO3.2]魔板 Magic Squares

松下問童子,言師採藥去。
只在此山中,雲深不知處。——賈島ios

題目:魔板 Magic Squares

網址:https://www.luogu.com.cn/problem/P2730編程

這是一張有8個大小相同的格子的魔板:數組

1 2 3 4編碼

8 7 6 5spa

題目描述

咱們知道魔板的每個方格都有一種顏色。這8種顏色用前8個正整數來表示。能夠用顏色的序列來表示一種魔板狀態,規定從魔板的左上角開始,沿順時針方向依次取出整數,構成一個顏色序列。code

對於上圖的魔板狀態,咱們用序列(1,2,3,4,5,6,7,8)來表示。
這是基本狀態。ip

這裏提供三種基本操做,分別用大寫字母「A」,「B」,「C」來表示(能夠經過這些操做改變魔板的狀態):字符串

「A」:交換上下兩行;get

「B」:將最右邊的一列插入最左邊;string

「C」:魔板中央四格做順時針旋轉。

下面是對基本狀態進行操做的示範:

A: 8 7 6 5

1 2 3 4

B: 4 1 2 3

5 8 7 6

C: 1 7 2 4

8 6 3 5

對於每種可能的狀態,這三種基本操做均可以使用。

你要編程計算用最少的基本操做完成基本狀態到目標狀態的轉換,輸出基本操做序列。

輸入格式

只有一行,包括8個整數,用空格分開(這些整數在範圍 1——8 之間)不換行,表示目標狀態。

輸出格式

Line 1: 包括一個整數,表示最短操做序列的長度。

Line 2: 在字典序中最先出現的操做序列,用字符串表示,除最後一行外,每行輸出60個字符。

輸入樣例
2 6 8 4 5 7 3 1
輸出樣例
7 
BCABCCB
說明

選自USACO Training Section 3.2

作完八數碼問題,不難理解這道題能夠使用廣搜解決(畢竟時間複雜度與八數碼問題相似)。

像以前的八數碼問題同樣,咱們把狀態定義成一個八位數,代碼中簡單的使用STL中map和set進行記錄與判重。

留意:本題有一個陷肼,若是使用從上到下、從左向右進行加和操做肯定狀態時,初狀態應爲:12348765!

代碼以下:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#include<set>
using namespace std;
const int rot[4] = {2, 1, 5, 6};
int st = 12348765, ed = 0, s[10];
map <int, int> d, f;
set <int> vis;
void decode(int state, int *p)
{
	for(int i = 7; i >= 0; -- i)
	{
		p[i] = state % 10;
		state /= 10;
	}
	//將十進制編碼轉化爲數組
	return;
}
int encode(int *p)
{
	int cnt = 0;
	for(int i = 0; i < 8; ++ i)
	{
		cnt = (cnt << 1) + (cnt << 3) + p[i];
	}
	//將數組轉化爲十進制8位編碼
	return cnt;
}
void flip(int cur, int *p)
{
	switch(cur)
	{
		case 0 :
		{
			for(int i = 0; i < 4; ++ i)
			{
				swap(p[i], p[i + 4]);
			}
			break;
		}
		case 1 :
		{
			for(int i = 2; i > -1; -- i)
			{
				swap(p[i], p[i + 1]);
				swap(p[i + 4], p[i + 5]);
			}
			break;
		}
		case 2 :
		{
			for(int i = 0; i < 3; ++ i)
			{
				swap(p[rot[i]], p[rot[i + 1]]);
			}
			break;
		}
	}
	return;
}
void print_ans(int state)
{
	if(state == st) return;
	int prev_state = 0;
	decode(state, s);
	switch(f[state])
	{
		case 0:
		{
			for(int i = 0; i < 4; ++ i)
			{
				swap(s[i], s[i + 4]);
            }
			break;
		}
		case 1:
		{
			for(int i = 0; i < 3; ++ i)
			{
				swap(s[i], s[i + 1]);
				swap(s[i + 4], s[i + 5]);
			}
			break;
		}
		case 2:
		{
			for(int i = 2; i >= 0; -- i)
			{
				swap(s[rot[i + 1]], s[rot[i]]);
            }
			break;
		}
	}
	for(int i = 0; i < 8; ++ i)
	{
		prev_state = prev_state * 10 + s[i];
	}
	memset(s, 0, sizeof(s));
	print_ans(prev_state);
	printf("%c", f[state] + 'A');
	return;
}
void bfs()
{
    //特判 初始狀態 和 目標狀態 相同
    if(st == ed) {
        puts("0");
        return;
    }
    
	f.clear(), vis.clear();
	queue <int> Q;
	while(!Q.empty()) Q.pop();
	
	Q.push(st);
	vis.insert(st);
	int copy[8] = {}, now, next;
	
	while(!Q.empty())
	{
		now = Q.front();
		Q.pop();
		decode(now, s);
		memcpy(copy, s, sizeof(copy));
		for(int i = 0; i < 3; ++ i)
		{
			flip(i, s);
			next = encode(s);
			memcpy(s, copy, sizeof(s));

			if(vis.count(next)) continue;
			d[next] = d[now] + 1;
			f[next] = i;
			if(next == ed)
			{
				printf("%d\n", d[next]);
				print_ans(next);
				return;
			}
			Q.push(next);
			vis.insert(next);
		}
	}
	return;
}
int main()
{
	memset(s, 0, sizeof(s));
	for(int i = 0; i < 4; ++ i) scanf("%d", &s[i]);
	//目標狀態處理:
	for(int i = 7; i >= 4; -- i) scanf("%d", &s[i]);
	//留意陷阱呢
	for(int i = 0; i < 8; ++ i)
	{
		ed = (ed << 1) + (ed << 3) + s[i];
	}
    bfs();
	return 0;
}
相關文章
相關標籤/搜索