您的位置:首页 > 其它

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

2014-08-20 11:58 387 查看




 一个正方体,每个面标了一个数字,问,这个正方体,在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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: