Fengshui(双向bfs看风水···)

先记录一个当时一时兴起想出来的歌谣:

风水算得好 小神有三宝

一宝曰广搜 阴阳五行 相生相克 探清形煞安福

二宝曰八维 八方八维 无穷幻变 洞察世事万千

三宝曰双向 由始向终 由终寻始 方得安居乐业


哈哈,这里提到了本题需要的几个关键词,广度搜索bfs,八维数组,双向bfs


Judge Info


  • Memory Limit: 32768KB
  • Case Time Limit: 10000MS
  • Time Limit: 30000MS
  • Judger: Normal


Description


Fengshui is an ancient subject in Chinese tradition. Someone considers it as science and someone criticizes it as blind faith. Who knows! However, in modern days, everyone should respect culture from our ancestor!


Fengshui focus on geography,environment and staffs' position, all the theory come from a very old book named "YI". YI means change. Everything is always changing in the world. Fengshui wishes to guide changing, make life change to a better situation. Now let's look at Fengshui's changing.


At first we must know about the traditional five elements system which composed by GOLD,WOOD,GROUND,WATER and FIRE. Everything in the world can be represented by one and only one element. For example, river is represented by WATER, hill is represented by GROUND. Here, we only consider the elements. In this system, once element can kill another element, and one element can born anther element. Five elements compose as a circuit, as in Figure 1.



Every place has eight direction - east, west, north, south, northeast, northwest, southeast and southwest. Every direction has a represented element. Now, our problem is about the elements at these eight directions which form a Fengshui situation. Figure 2 is an example of one Fengshui situation.


  • But Fengshui situation can change! There're two change ways:
    • TURN: The whole situation turn clockwise one step. Figure 3 shows the situation that situation in Figure 2 makes one TURN change.
    • REBORN: Based on kill and born relation, one direction's element can be killed by another direction's (at any other place) element in the situation, and then the killed element will born out as the new element at its direction. Of course, kill and born are all according as the relation of the system as in Figure 1. In situation of Figure 3, WATER in east can kill FIRE in southeast, then southeast place change to be GROUND, as in Figure 4.



Each change, no matter TURN or REBORN, const one step.


Now, there're two Fengshui situation, we want to know is it possible that first one can change to the second one? And if possible, how many steps it need at least?


Input


There're several cases, the first line of input is the number of cases. Every case includes 6 lines, the first 3 lines indeicate the first Fengshui situation, the last 3 lines incicate the second Fengshui situation.


The format of one situation is as follow, there may be arbitrary blanks between adjacent directions.

northwest  north  northeast
west                   east
southwest  south  southeast


Output


For every case, output the number of the least changing steps on a single line, if it is possible, or output -1.


Sample Input

2
GOLD WOOD WATER
WATER     FIRE
WOOD GOLD GROUND
WATER GOLD WOOD
WOOD       WATER
GOLD GROUND GROUND
WATER GROUND WOOD
GOLD         FIRE
GOLD  FIRE   GROUND
GOLD  FIRE   FIRE
GOLD         FIRE
WATER GROUND WOOD


Sample Output

2 
14


题意就是输入两组八个方向的五行,然后通过两组规则“转向”和“再生”进行变换,看看第一组风水图最少需要几次变换才能变成第二组图,不行就-1

这里我们先用map库里的map把五行映射成数字,方便我们计算

接下来对其进行九个方向的广搜,内容为转向和八种再生,介于本题的时间要求,我们必须使用双向bfs。即对起点进行正向搜索,对结尾进行反向搜索直到他们接触到彼此。不过要小心触碰时的细节,还有队列要开大点不然很容易溢出。记得用八维的bool数组记录变化情况。

#include<iostream>
#include<map>
#include<string>
#include<memory.h>
using namespace std;
char v[5][5][5][5][5][5][5][5];
int s[8],e[8];
 
bool issame(int *a,int *b)//判断两个序列是否相同
{
	bool flag=1;
	for(int i=0;i<8;i++)
	if(a[i]!=b[i])
	{
		flag=0;
		break;
	}
	return flag;
}
 
void Turn(int *a,int *b)//顺时针转向
{
	b[0]=a[7];
	for(int i=1;i<8;i++)
	b[i]=a[i-1];
}
 
void reTurn(int *a,int *b)//逆时针转向
{
	b[7]=a[0];
	for(int i=0;i<7;i++)
	b[i]=a[i+1];
}
 
bool canReborn(int *a,int n)//能否再生
{
	bool flag=0;
	for(int i=0;i<8;i++)
	if(a[i]==(a[n]+4)%5)
	{
		flag=1;
		break;
	}
	return flag;
}
 
bool canBorn(int *a,int n)//能否反向再生
{
	bool flag=0;
	for(int i=0;i<8;i++)
	if(a[i]==(a[n]+1)%5)
	{
		flag=1;
		break;
	}
	return flag;
}
 
void Reborn(int *a,int n,int *b)//再生
{
	for(int i=0;i<8;i++)
	b[i]=a[i];
	b[n]=(a[n]+3)%5;
}
 
void Born(int *a,int n,int *b)//反向再生
{
	for(int i=0;i<8;i++)
	b[i]=a[i];
	b[n]=(a[n]+2)%5;
}
 
struct line
{
	int fengshui[400000][9];//每个点存储八个数字和一个步数
	int *p;
	int *q;
	line()
	{
		p=fengshui[0];
		q=fengshui[0];
	}
	void push(int t,int* a)
	{
		for(int i=0;i<8;i++)
		q[i]=a[i];
		q[8]=t;
		q+=9;
	}
	void pop()
	{
		p+=9;
	}
	int *ask()
	{
		return p;
	}
	bool isnull()
	{
		if(p==q)
		return true;
		else
		return false;
	}
	void initialize()
	{
		p=fengshui[0];
		q=fengshui[0];
	}
 
};
 
line sl,el;//正反两个序列
 
int main()
{
	map<string,int> wuxing;//简单的map映射
	wuxing["GOLD"]=0;
	wuxing["WOOD"]=1;
	wuxing["GROUND"]=2;
	wuxing["WATER"]=3;
	wuxing["FIRE"]=4;
	int n;
	cin>>n;
	while(n--)
	{
		string wx;
		for(int i=0;i<3;i++)
		{
			cin>>wx;
			s[i]=wuxing[wx];
		}
		cin>>wx;
		s[7]=wuxing[wx];
		cin>>wx;
		s[3]=wuxing[wx];
		for(int i=6;i>3;i--)
		{
			cin>>wx;
			s[i]=wuxing[wx];
		}
		for(int i=0;i<3;i++)
		{
			cin>>wx;
			e[i]=wuxing[wx];
		}
		cin>>wx;
		e[7]=wuxing[wx];
		cin>>wx;
		e[3]=wuxing[wx];
		for(int i=6;i>3;i--)
		{
			cin>>wx;
			e[i]=wuxing[wx];
		}//由于用户输入不是顺时针的,所以次序有点乱
		sl.initialize();
		el.initialize();
		int t1=0,t2=0;
		sl.push(0,s);
		el.push(0,e);
		int flag=0; 
		int fs[8];
		int xl[8];
		int *p;
		if(issame(s,e))
		{
			cout<<0<<endl;
			continue;
		}
		else
		{
			memset(v,0,390625*sizeof(char));
			v[s[0]][s[1]][s[2]][s[3]][s[4]][s[5]][s[6]][s[7]]=1;
			v[e[0]][e[1]][e[2]][e[3]][e[4]][e[5]][e[6]][e[7]]=2;
		}
		while(!flag)
		{
			while(!flag&&!sl.isnull()&&(p=sl.ask())[8]==t1)
			{
				sl.pop();
				for(int i=0;i<8;i++)
				fs[i]=p[i];
				Turn(fs,xl);
				if(v[xl[0]][xl[1]][xl[2]][xl[3]][xl[4]][xl[5]][xl[6]][xl[7]]!=1)
				{
					v[xl[0]][xl[1]][xl[2]][xl[3]][xl[4]][xl[5]][xl[6]][xl[7]]++;
					if(v[xl[0]][xl[1]][xl[2]][xl[3]][xl[4]][xl[5]][xl[6]][xl[7]]==3)
					{
						flag=1;
						break;
					}
					sl.push(t1+1,xl);
				}
				for(int i=0;!flag&&i<8;i++)
				{
					if(canReborn(fs,i))
					{
						Reborn(fs,i,xl);
						if(v[xl[0]][xl[1]][xl[2]][xl[3]][xl[4]][xl[5]][xl[6]][xl[7]]!=1)
						{
							v[xl[0]][xl[1]][xl[2]][xl[3]][xl[4]][xl[5]][xl[6]][xl[7]]++;
							if(v[xl[0]][xl[1]][xl[2]][xl[3]][xl[4]][xl[5]][xl[6]][xl[7]]==3)
							{
								flag=1;
								break;
							}
							sl.push(t1+1,xl);
						}
					}
				}
			}
			if(flag!=1)
			{
				if(sl.isnull()) flag=2;
			}
			while(!flag&&!el.isnull()&&(p=el.ask())[8]==t2)
			{
				el.pop();
				for(int i=0;i<8;i++)
				fs[i]=p[i];
				reTurn(fs,xl);
				if(v[xl[0]][xl[1]][xl[2]][xl[3]][xl[4]][xl[5]][xl[6]][xl[7]]!=2)
				{
					v[xl[0]][xl[1]][xl[2]][xl[3]][xl[4]][xl[5]][xl[6]][xl[7]]+=2;
					if(v[xl[0]][xl[1]][xl[2]][xl[3]][xl[4]][xl[5]][xl[6]][xl[7]]==3)
					{
						flag=3;
						break;
					}
					el.push(t2+1,xl);
				}
				for(int i=0;!flag&&i<8;i++)
				{
					if(canBorn(fs,i))
					{
						Born(fs,i,xl);
						if(v[xl[0]][xl[1]][xl[2]][xl[3]][xl[4]][xl[5]][xl[6]][xl[7]]!=2)
						{
							v[xl[0]][xl[1]][xl[2]][xl[3]][xl[4]][xl[5]][xl[6]][xl[7]]+=2;
							if(v[xl[0]][xl[1]][xl[2]][xl[3]][xl[4]][xl[5]][xl[6]][xl[7]]==3)
							{
								flag=3;
								break;
							}
							el.push(t2+1,xl);
						}
					}
				}
			}
			if(flag==0)
			{
				if(el.isnull()) flag=2;
				else
				{
					t1++;
					t2++;
				}
			}
		}
		if(flag==1) cout<<t1+t2+1<<endl;
		else if(flag==3) cout <<t1+t2+2<<endl;
		else cout<<-1<<endl;
	}
	return 0;
}


广搜的细节很多,反正现在看到广搜真心有种想吐的感觉。。。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值