[USACO3.2]Magic Squares 魔板

题目大意

给出一个2*4的矩阵,有3种基本操作

A B C
交换上下两行 将最右边的一列插入最左边 中央四格作顺时针旋转

基本状态:
1 2 3 4
8 7 6 5
给定一个目标状态,求最少的基本操作完成基本状态到目标状态的转换,输出基本操作序列。

题目解析

该题目很明显是用搜索做,如果用深搜,则会超时,所以只能用宽搜。
但是如果没有一种好的方法来判断是否已经加入列表,可能会超时,所以,哈希表。

代码

#include<iostream>
#include<string>
#define p 100003//质数 
using namespace std;
int x,f[p],num[p],head,tail=1;//f标记父节点   num表示当前状态的最少操作数 
int r[3][8]={{8,7,6,5,4,3,2,1},{4,1,2,3,6,7,8,5},{1,7,2,4,5,3,6,8}};//变换的规则 
char ans[p];//存储 A B C 
string g,a[p],state[p];//g为目标状态 
bool hash(string s)//哈希函数
{
	int k=0,i=0;
	for(int i=0;i<8;i++)
	 k=k*10+s[i]-48;
	k%=p;
	while(a[(k+i)%p]!=""&&a[(k+i)%p]!=s)
	 i++;
	if(a[(i+k)%p]=="")
	{
	  a[(i+k)%p]=s;
	  return false;
	}
	return true;
} 
void bfs()
{
	hash("12345678");
	state[1]="12345678";//初始化 
	do
	{
	  head++;
	  for(int i=0;i<3;i++)
	  {
	  	tail++;
	  	f[tail]=head;
	  	state[tail]="";
	  	num[tail]=num[head]+1;
	  	ans[tail]='A'+i;
	  	for(int j=0;j<8;j++)
	  	 state[tail]+=state[head][r[i][j]-1];//字符串从0为开始算 
	  	if(hash(state[tail])) tail--;//判断是否能够入队 
	  	else if(state[tail]==g) return;//找到目标状态 
	  }
	}while(head<tail);
}
void out(int x)//输出 
{
	if(x==1) return;
	out(f[x]);
	cout<<ans[x];
}
int main()
{
	for(int i=1;i<=8;i++)
	{
	  cin>>x;
	  g+=x+48;
	}//目标状态转换为字符串 
	if(g=="12345678") 
	{
	  cout<<0;
	  return 0;
	}//特判 
	bfs();//宽搜 
	cout<<num[tail]<<endl;
	out(tail);
}

猜你喜欢

转载自blog.csdn.net/weixin_43909855/article/details/85370257
今日推荐