poj 2286 IDA*搜索

/*
题意:给出一个井字的图案,上面有且只有8个1,8个2,8个3,可以从A~H8个方向拉某行/列,问最少拉多少次使得
中间的8个方格的数字相同

题解:IDA_STAR
关键在实现的方法,通过用一个position的二维数组分别记录4条的对应位置,8个方向搜索,由于每一个点都要记录
当时的情况

注意:往某个方向拉了一格之后,下一层搜索就不应该包含此次的相反方向,避免来回重复搜索;
*/
#include <cstdio>
#include <cstring>
#include <algorithm>

int position[4][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}; // 分别按照4条方格记录位置
int mark[24]; // 记录图的值
int midpos[8] = {6,7,8,11,12,15,16,17}; // 中间框的位置
int re[8] = {5,4,7,6,1,0,3,2}; // 8个方向对应的反方向
int ans,ansdepth;
char ansstr[10005]; // 最终的字符串

int lstdepth; // IDA_STAR算法时的搜索的深度(不严谨的说法)

int minnum(int *pmark) // 估价函数,求最少还差多少个数可以满足条件
{
    int sum1,sum2,sum3;
    sum1 = sum2 = sum3 = 0;
    for(int i=0; i<8; i++)
    {
        if (1 == pmark[midpos[i]])
            sum1++;
        else if (2 == pmark[midpos[i]])
            sum2++;
        else if (3 == pmark[midpos[i]])
            sum3++;
    }
    int ret = sum1;
    if (ret < sum2)
        ret = sum2;
    if (ret < sum3)
        ret = sum3;
    return 8 - ret;
}

int dfs(int depth, int *pmark, int predir)
{
    int mint = minnum(pmark);
    if (depth + mint > lstdepth) // 搜索到lstdepth时回溯
    {
        return depth + mint;
    }
    if (mint == 0)
    {
        ans = pmark[6];
        ansdepth = depth;
        return depth;
    }
    int mindepth = 1 << 30; // 每一次都求出后面的结点中最小的估价
    for(int i=0; i<8; i++)
    {
        if (predir == i)
            continue;
        int tmpmark[24];
        for(int j=0; j<24; j++)
            tmpmark[j] = pmark[j];
        if (i < 4)
        {
            int t = tmpmark[position[i][0]];
            for(int j=1; j<7; j++)
                tmpmark[position[i][j-1]] = tmpmark[position[i][j]];
            tmpmark[position[i][6]] = t;
        }
        else
        {
            int c;
            if (4 == i)
                c = 1;
            else if (5 == i)
                c = 0;
            else if (6 == i)
                c = 3;
            else if (7 == i)
                c = 2;
            int t = tmpmark[position[c][6]];
            for(int j=5; j>=0; j--)
                tmpmark[position[c][j+1]] = tmpmark[position[c][j]];
            tmpmark[position[c][0]] = t;
        }
        ansstr[depth] = i+'A';
        int nextdepth = dfs(depth+1, tmpmark, re[i]);
        mindepth = std::min(nextdepth, mindepth);
        if (ans)
            return 0;
    }
    return mindepth;
}

int main(void)
{
    while (~scanf("%d",&mark[0]) && mark[0])
    {
        for(int i=1; i<24; i++)
            scanf("%d",&mark[i]);
        ans = ansdepth = 0;
        lstdepth = minnum(mark);
        ansstr[0] = 0;
        while (ans == 0 && lstdepth <= 100)
        {
            lstdepth = dfs(0,mark,-1);
        }
        if (ansdepth == 0)
            printf("No moves needed");
        else
        {
            for(int i=0; i<ansdepth; i++)
                printf("%c",ansstr[i]);
        }
        printf("\n%d\n",ans);
    }
    return 0;
}

 

posted @ 2014-03-22 18:29  辛力啤  阅读(235)  评论(0编辑  收藏  举报