UVA-1343 The Rotation Game (IDA*)

题目大意:数字1,2,3都有八个,求出最少的旋转次数使得图形中间八个数相同。旋转规则:对于每一长行或每一长列,每次旋转就是将数据向头的位置移动一位,头上的数放置到尾部。若次数相同,则找出字典序最小旋转次序。

题目分析:IDA*,若当前在第cur层,中间八个数中1,2,3的个数分别为a,b,c。则d=8-max(a,b,c)便是达到目标还需要的理想次数,若cur+d>maxd,则剪枝。《入门经典》上提供了一种BFS的思路,分别以1,2,3为目标广搜3次,不过自己的码力还是太弱,并没有用那种方法AC。。。!!!

 

代码如下:

# include<iostream>
# include<cstdio>
# include<queue>
# include<cstring>
# include<algorithm>
using namespace std;

int a[24],d[8][7]={
    {0,2,6,11,15,20,22},
    {1,3,8,12,17,21,23},
    {10,9,8,7,6,5,4},
    {19,18,17,16,15,14,13},
    {23,21,17,12,8,3,1},
    {22,20,15,11,6,2,0},
    {13,14,15,16,17,18,19},
    {4,5,6,7,8,9,10},
};
int g[8]={6,7,8,11,12,15,16,17};
int ans;
string ansp;

bool dfs(int cur,int maxd,string path)
{
    if(cur==maxd){
        int ok=1;
        for(int i=1;i<8;++i)
            if(a[g[i]]!=a[g[i-1]]){
                ok=0;
                break;
            }
        if(!ok)
            return false;
        ans=a[g[0]],ansp=path;
        return true;
    }
    int b[3]={0,0,0};
    for(int i=0;i<8;++i)
        ++b[a[g[i]]-1];
    int dd=8-max(max(b[0],b[1]),b[2]);
    if(cur+dd>maxd)
        return false;
    for(int i=0;i<8;++i){
        int v=a[d[i][0]];
        for(int j=0;j<6;++j)
            a[d[i][j]]=a[d[i][j+1]];
        a[d[i][6]]=v;
        if(dfs(cur+1,maxd,path+char(i+'A')))
            return true;
        v=a[d[i][6]];
        for(int j=6;j>0;--j)
            a[d[i][j]]=a[d[i][j-1]];
        a[d[i][0]]=v;
    }
    return false;
}

int main()
{
    while(scanf("%d",&a[0])&&a[0])
    {
        for(int i=1;i<24;++i)
            scanf("%d",a+i);

        ans=-1;
        for(int maxd=0;;++maxd){
            if(dfs(0,maxd,"")){
                if(maxd==0)
                    printf("No moves needed\n");
                else
                    cout<<ansp<<endl;
                printf("%d\n",ans);
                break;
            }
        }
    }
    return 0;
}

  

posted @ 2015-09-24 00:19  20143605  阅读(438)  评论(0编辑  收藏  举报