URAL 1016. Cube on the Walk (分层图+最短路)

URAL 1016. Cube on the Walk (分层图+最短路)_第1张图片

 一个正方体,每个面标了一个数字,问,这个正方体,在8*8的棋盘上,从起点滚动到终点,所有朝下的面的数字之和的最小值(包括起点和终点)。

正方体,经过旋转,最多有24种状态。建立分层图,点数:24*8*8=1536.  稀疏图,用 SPFA 算法求最短路。

我直接写的一维数组。节点编号= 正方体的状态*64 +横坐标*8 +纵坐标 ;

开始求出所有24个状态(特殊情况可能少于24种状态)之间的状态转移。

然后SPFA求最短路。

using namespace std;
int dx[4]={-1, 1, 0, 0};
int dy[4]={ 0, 0, 1,-1};
int de[4]={ 5, 3, 1, 0};
struct Dice{
	int a[6];//按照题目给的顺序,分别为前,后,上,右,下,左 
	int next[4];//四个方向旋转后的编号
	void turn(int i){
		switch(i){
			case 0:left();break;
			case 1:right();break;
			case 2:up();break;
			case 3:down();break;
		}
	}
	void left(){int t=a[5];a[5]=a[2];a[2]=a[3];a[3]=a[4];a[4]=t;}//向左滚动
	void right(){int t=a[5];a[5]=a[4];a[4]=a[3];a[3]=a[2];a[2]=t;}//向右滚动
	void up(){int t=a[0];a[0]=a[4];a[4]=a[1];a[1]=a[2];a[2]=t;}//向上滚动
	void down(){int t=a[0];a[0]=a[2];a[2]=a[1];a[1]=a[4];a[4]=t;}//向下滚动
	bool operator ==(const Dice&B)const{
		int T=0;
		for(int i=0;i<6;i++) T+=a[i]==B.a[i];
		return T==6;
	}
	void show(){
		printf("\t(%d,%d,%d,%d,%d,%d)\n",a[0],a[1],a[2],a[3],a[4],a[5]);
	}
}D[24];int Dn;//记录24种状态
struct Node{
	int path;//记录最短路径
	int Dis;//记录最小值
	void init(int k){
		Dis=-1;path=k;
	}
}game[1536];
queue<int> Q;
bool inq[1536];
void Bfs(int k){
	int tempk=k;
	int index=tempk/64;tempk%=64;
	int x=tempk/8,y=tempk%8;
	for(int i=0;i<4;i++){//向4个方向扩展 
		int nx=x+dx[i],ny=y+dy[i];
		int Next=D[index].next[i]*64+nx*8+ny;//计算下个节点的编号 
		if(nx>=0&&nx<8&&ny>=0&&ny<8){//如果下一点在棋盘内 
			int Distance=game[k].Dis+D[index].a[de[i]];
			if(!~game[Next].Dis||Distance<game[Next].Dis){//如果未走过或者路径更短,更新 
				game[Next].Dis=Distance;
				game[Next].path=game[k].path;
				game[Next].path=k;
				if(!inq[Next]) Q.push(Next),inq[Next]=1;//若未入队,入队 
			}
		}
	}
}
void F(int i){//输出路径 
	if(i!=game[i].path) F(game[i].path);
	int t=i%64;
	printf(" %c%c",t/8+'a',t%8+'1');
}
int main(void)
{
	//处理输入 
	string a;int Sx,Sy,Dx,Dy;
	cin>>a;Sx=a[0]-'a';Sy=a[1]-'1';
	cin>>a;Dx=a[0]-'a';Dy=a[1]-'1';
	for(int i=0;i<6;i++) scanf("%d",&D[0].a[i]);
	//求出24状态之间的状态转移。
	Dn=1;
	for(int i=0;i<Dn;i++){//对于每个状态(开始只有一个状态) 
		for(int k=0;k<4;k++){// 向四个方向滚动 
			Dice temp=D[i];
			temp.turn(k);//记录滚动后的状态
			int Target=-1;
			for(int j=0;j<Dn;j++){//若出现过,记录编号
				if(D[j]==temp) {
					Target=j;break;
				}
			}
			if(!~Target){//若没出现过,用新的编号 
				Target=Dn++;
				D[Target]=temp;
			}
			D[i].next[k]=Target;//记录i往四个方向转动后的状态的编号 
		}
	}
	//显示Dices
	/* 
	for(int i=0;i<Dn;i++){
		printf("%d:",i);D[i].show();
		for(int k=0;k<4;k++) printf("->%d",D[i].next[k]);
		cout<<endl;
	}*/
	
	//计算  (SPFA)
	for(int i=0;i<1536;i++) game[i].init(i);
	memset(inq,0,sizeof(inq));
	Q.push(Sx*8+Sy);inq[Sx*8+Sy]=1;
	game[Sx*8+Sy].Dis=D[0].a[4];
	while(!Q.empty()){
		int cnt=Q.front();Q.pop();
		inq[cnt]=0;
		Bfs(cnt);
	}
	//搜索答案 
	int ANS=-1;int ANSI=-1;
	for(int i=0;i<Dn;i++){//搜索每一层
		if(~game[i*64+Dx*8+Dy].Dis){//如果可以到达
			if(!~ANS||game[i*64+Dx*8+Dy].Dis<ANS){//ANS未找到,或者新距离小于原始ANS  则更新。
				ANS=game[i*64+Dx*8+Dy].Dis;
				ANSI=i*64+Dx*8+Dy;
			}	
		}
	}
	//输出答案 
	cout<<ANS;
	F(ANSI);
	cout<<endl;
return 0;
}




你可能感兴趣的:(URAL 1016. Cube on the Walk (分层图+最短路))