【C++心路历程34】【HDU1667】【POJ2286】【UVA1343紫书210例题】the rotation game

来源:互联网 发布:游戏cg制作软件 编辑:程序博客网 时间:2024/06/10 02:23

【问题描述】

  如下图所示形状的棋盘上分别有8个1,8个2,8个3。在图上标明了8种旋转方式:每种旋转方式包含旋转方向和旋转的是拿一列或行。
  
  (没有图 很尴尬)



  现在需要把棋盘经过若干次旋转,使得中间8个方格中的数字相同,例如下图,先进行一次A方式的旋转,再进行一次C方式的旋转后,棋盘中间的8个方格的数字都是2。
  
  现在需要你对给出的棋盘的初始状态和目标状态,需要旋转最少的次数从初始状态变到目标状态,如果有多种旋转方式,输出字典序最小的。

【输入格式】

  最多不超过30组数据,每组数据含一行,表示棋盘的初始状态,包含24个整数:1,2,3,对应棋盘从上到下,从左到右的每个格子的数字。输入以0结束。 

【输出格式】

  每组数据输出2行,第一行字典序最小的旋转操作序列(如果不需要任何操作,请输出“No moves needed”),第二行为棋盘目标状态中间8个方格中的数字。

【输入样例】

1 1 1 1 3 2 3 2 3 1 3 2 2 3 1 2 2 2 3 1 2 1 3 3
1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3
0

【输出样例】

AC
2
DDHH
2

【样例解释】

每个测试点不超过30组数据。

【分析】
紫书上爆搜蛮好,这里用A*算法写。
因为题目所求“最少步数”,正好符合DFSID模型。
主程序:

void solve(){    if(check())     {        printf("No moves needed\n");        printf("%d\n",a[3][3]);        return;    }    for(maxd=0;;maxd++)    {        if(DFSID(1)) break;    }    for(int i=1;i<=maxd;i++)    {        printf("%c",ans[i]);    }       printf("\n%d\n",a[3][3]);}

//DFSID
//小技巧:恢复A操作可视为F操作,以此类推,可以少写许多函数并节省空间

bool DFSID(int i){    if(i>maxd)    {        if(check()) return true;        return false;    }    //估价    //依次处理ABCDEFGH操作,并恢复    //小技巧:恢复A操作可视为F操作,以此类推,可以少写许多函数并节省空间    return false;

估价函数分析:因为每次变换最多只改变一个错误位置,所以在中间8个数中,现在将最大的数视为“正确的”,设有maxd个,那也得至少改变8-maxd次才有可能达到目标状态。

//  估价函数:每次移动最多改变1个错误的位置     int vis[4]={0,0,0,0};    vis[a[3][3]]++;vis[a[3][5]]++;    vis[a[3][4]]++;vis[a[4][5]]++;    vis[a[5][3]]++;vis[a[5][4]]++;    vis[a[5][5]]++;vis[a[4][3]]++;    int h=8-max(vis[1],max(vis[3],vis[2]));//错误的数目     if(i-1+h>maxd) return false;    //前i-1步 和至少还要走h步(估价函数)
阅读全文
0 0
原创粉丝点击