posts - 0,comments - 0,trackbacks - 0

又是骰子。。最近见到骰子的状态就头痛。。更要命的是这个骰子还带滚的。。
其实可以把转的步数做状态来动归,但考虑到要输出路径,本菜还是觉得用搜索比较实在。
先可以把所有的6个面的数字编号做个预处理(允许重复)have[a1][b1][c1][d1][e1][f1]表示该骰子(不管是否合法,就算6个面都是前面也算)在第几个状态
v[i][6]表示第i个骰子的各个面的数字编号v[3][2]=4就表示第三个骰子的右面是原来前面。(我的顺序是左、右、上、前、下、后)。
从第一个开始搜索,第一状态肯定是have[1][2][3][4][5][6],按照4个方向滚一遍,添加新的状态入队。
这里可以有个类似spfa的优化,做一个标记数组表示该状态是否在队列里,为0表示不在,不为0就是在,这是bj的值就是该状态在队列中的位置。
对于一个没有到达过的状态,直接入队,如果到达过,能更新最小值就更新入队(如果不在队列中)。
关于路径的问题很容易,如果有状态入队了,那么它的前驱pri就是当前的head,如果更新已在队列中的状态的最小值,那么根据bj找到状态的位置,将这个位置的前驱标记为head。
每当到了目标点时,更新最小值,如果更新了,就额外用一个变量记录目标点的前驱。
搜索完了以后,根据记录的目标点的前驱递归输出路径。

#include<stdio.h>
typedef 
struct duitype
{
  
long x,y,z;
}duitype;
duitype dui[
10000];
long pre[10000];
long jl[7][7][7][7][7][7];
long temp[7];
long vv[7];
long v[46657][7];
long bj[9][9][46657];
long have[9][9][46657];
long aa,a1,b1,c1,d1,e1,f1,a2,b2,head,last,x,y,z,top,i,ans,k,j,place,zz;
void cha(long a,long b,long c,long d)
{
  
long t;
  t
=temp[a];
  temp[a]
=temp[b];
  temp[b]
=temp[c];
  temp[c]
=temp[d];
  temp[d]
=t;
}
long change(long z,char c)
{
  
long i;
  
for (i=1;i<=6;i++)
    temp[i]
=v[z][i];
  
switch(c)
  {
    
case 'l':cha(6,3,4,5);break;
    
case 'r':cha(4,3,6,5);break;
    
case 'u':cha(1,5,2,3);break;
    
case 'd':cha(1,3,2,5);break;
  }
  
return jl[temp[1]][temp[2]][temp[3]][temp[4]][temp[5]][temp[6]];
}
void ind(long x,long y,long z,long all,char c)
{
  
long ne;
  
if (x<=0 || x>8 || y<=0 || y>8)
    
return;
  ne
=change(z,c);
  
if (bj[x][y][ne]==0 && have[x][y][ne]>all+v[ne][5])//不在队列中
  {
    last
++;
    dui[last].x
=x;
    dui[last].y
=y;
    dui[last].z
=ne;
    pre[last]
=head;
    have[x][y][ne]
=all+vv[v[ne][5]];
    bj[x][y][ne]
=last;
  } 
  
else
  {
    
if (have[x][y][ne]>all+vv[v[ne][5]])//在队列中判能否更新最小值
     {
      have[x][y][ne]
=all+vv[v[ne][5]];
      pre[bj[x][y][ne]]
=head;
     }
  }   
  
if (x==a2 && y==b2)//到了目标点 用place额外记录前驱
    if (ans>have[x][y][ne])
    {
      ans
=have[x][y][ne];
      place
=head;
    }
}
void getprint(long head)
{
  
if (dui[head].x==a1 && dui[head].y==b1 && dui[head].z==zz)
  {
    printf(
"%c%c ",a1+96,b1+48);
    
return;
  }
  getprint(pre[head]);
  printf(
"%c%c ",dui[head].x+96,dui[head].y+48);
}
int main()
{
  
for (a1=1;a1<=6;a1++)
    
for (b1=1;b1<=6;b1++)
      
for (c1=1;c1<=6;c1++)
        
for (d1=1;d1<=6;d1++)
          
for (e1=1;e1<=6;e1++)
            
for (f1=1;f1<=6;f1++)
            {
              top
++;jl[a1][b1][c1][d1][e1][f1]=top;
              v[top][
1]=a1;v[top][2]=b1;v[top][3]=c1;v[top][4]=d1;v[top][5]=e1;v[top][6]=f1;
            } 
//预处理
  for (i=1;i<=8;i++)
    
for (j=1;j<=8;j++)
      
for (k=1;k<=46656;k++)
        have[i][j][k]
=10000000;
  ans
=10000000;
  scanf(
"%c%c%c%c%c",&a1,&b1,&aa,&a2,&b2);
  a1
-=96;a2-=96;b1-=48;b2-=48;
  
for (i=1;i<=6;i++)
    scanf(
"%d",&vv[i]);
  z
=zz=jl[1][2][3][4][5][6]; 
  head
=0;last=1;dui[1].x=a1;dui[1].y=b1;dui[1].z=z;
  bj[a1][b1][z]
=1;have[a1][b1][z]=vv[v[z][5]];//状态为X,Y坐标,第Z个骰子状态
  while (head<last)
  {
    head
++;
    x
=dui[head].x;y=dui[head].y;z=dui[head].z;
    bj[x][y][z]
=0;//该状态离队
    ind(x+1,y,z,have[x][y][z],'r');
    ind(x
-1,y,z,have[x][y][z],'l');
    ind(x,y
+1,z,have[x][y][z],'u');
    ind(x,y
-1,z,have[x][y][z],'d');
  }
  printf(
"%ld ",ans);
  getprint(place);
  printf(
"%c%c",a2+96,b2+48);
}


 

posted on 2011-06-27 18:34 梦转千寻 阅读(121) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航:   博客园   博客园最新博文   博问   管理