HDU 无题I (IDA*)

无题I

Time Limit : 10000/10000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 16   Accepted Submission(s) : 8
Problem Description
一天机器人小A在玩一个简单的智力游戏,这个游戏是这样的,在一个4*4的矩阵中分别有4个1,4个2,4个3和4个4分别表示4种不同的东西,每一步小A可以把同一行的4个数往左移或者往右移一步或者把同一列的4个数字往上移或者往下移一步(1,2,3,4往左移后是2,3,4,1),小A现在想知道进过最少的几步移动可以将矩阵的每行上的4个数字都一样或者每列上的4个数字都一样。但是小A又不想走太多步,他只要知道最少步数是否少于等于5步,是的话输出准确的步数,否则输出-1。
 
Input
先输入一个整数T,表示有T组数据。 对于每组数据输入4行,每行4列表示这个矩阵。
 
Output
对于每组输入输出一个正整数表示最少的移动步数,大于5则输出-1.
 
Sample Input
2
1 2 3 4 1 2 3 4 1 2 3 4 2 3 4 1
4 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4
 
Sample Output
1 1
 
Source
HDOJ 2008 Summer Exercise(2)- Hold by Captain Xu
 
 
 

有16种变化,但是是有规律的,不需要一一列出。每次变化改变4个位置,估价函数是,最少的可能不满足要求的个数+3/4和上题有点像。

跑进了2s内,还不错,不知道31ms是怎么写的。

其中IDA*搜索的时候还是用到了父节点优化,比如上一步是第一列向上,那么下一步不会做第一列向下。

 

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

const int INF=0x3f3f3f3f;

int a[4][4];
int depth,flag;

void change(int b[4][4],int k){
    if(k<8){
        if(k&1){
            int tmp=b[0][k/2];
            for(int i=1;i<4;i++)
                b[i-1][k/2]=b[i][k/2];
            b[3][k/2]=tmp;
        }else{
            int tmp=b[3][k/2];
            for(int i=3;i>0;i--)
                b[i][k/2]=b[i-1][k/2];
            b[0][k/2]=tmp;
        }
    }else{
        if(k&1){
            int tmp=b[(k-8)/2][0];
            for(int j=1;j<4;j++)
                b[(k-8)/2][j-1]=b[(k-8)/2][j];
            b[(k-8)/2][3]=tmp;
        }else{
            int tmp=b[(k-8)/2][3];
            for(int j=3;j>0;j--)
                b[(k-8)/2][j]=b[(k-8)/2][j-1];
            b[(k-8)/2][0]=tmp;
        }
    }
}

int H(int b[4][4]){
    int ans=INF,tmp=0;
    int flag[5],cnt;
    for(int i=0;i<4;i++){
        cnt=4;
        memset(flag,0,sizeof(flag));
        for(int j=0;j<4;j++)
            if(!flag[b[i][j]]){
                cnt--;
                flag[b[i][j]]=1;
            }
        tmp+=3-cnt;
    }
    ans=min(ans,tmp);
    tmp=0;
    for(int j=0;j<4;j++){
        cnt=4;
        memset(flag,0,sizeof(flag));
        for(int i=0;i<4;i++)
            if(!flag[b[i][j]]){
                cnt--;
                flag[b[i][j]]=1;
            }
        tmp+=3-cnt;
    }
    ans=min(ans,tmp);
    return (ans+3)/4;  //这里不理解
}

void IDAstar(int b[4][4],int curDepth,int dir){
    if(flag)
        return ;
    if(H(b)>curDepth)
        return ;
    if(curDepth==0){
        flag=1;
        return ;
    }
    for(int i=0;i<16;i++){
        if(dir!=-1 && dir/2==i/2 && (dir%2)^(i%2))  //上一步是第一列向上,那么下一步不会做第一列向下
            continue;
        int tmp[4][4];
        for(int j=0;j<4;j++)
            for(int k=0;k<4;k++)
                tmp[j][k]=b[j][k];
        change(tmp,i);
        IDAstar(tmp,curDepth-1,i);
    }
}

int main(){

    //freopen("input.txt","r",stdin);

    int t;
    scanf("%d",&t);
    while(t--){
        int i,j;
        for(i=0;i<4;i++)
            for(j=0;j<4;j++)
                scanf("%d",&a[i][j]);
        flag=0;
        for(depth=0;depth<=5;depth++){
            IDAstar(a,depth,-1);
            if(flag){
                printf("%d\n",depth);
                break;
            }
        }
        if(!flag)
            printf("-1\n");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/jackge/p/3030613.html