hdu 2234 无题I (IDA*+dfs)

来源:互联网 发布:枪械原理的软件 编辑:程序博客网 时间:2024/05/16 12:23

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2234

无题I

Time Limit: 10000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1377    Accepted Submission(s): 532


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
21 2 3 41 2 3 41 2 3 42 3 4 14 1 1 11 2 2 22 3 3 33 4 4 4
 

Sample Output
11
 

Source
HDOJ 2008 Summer Exercise(2)- Hold by Captain Xu
 

Recommend
lcy   |   We have carefully selected several similar problems for you:  1560 1667 1813 1043 1401 

题目大意:要求每行或者每列的全部相同,输出最小改变的步数。
特别注意:
1、最少步数是否少于等于5步,是的话输出准确的步数,否则输出-1。
2、通过get_h()估计函数得到理想状态下的最小步数。
3、最少的可能不满足要求的个数+3/4
4、IDA*将所有可以的方向都走一遍,不可以在改变回原有状态


详见代码。
#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <algorithm>using namespace std;int a[10][10],want;int get_h()//即h()=(最少可能的横向或纵向不在位置上的点的个数+3)/4 ){    int tmp1=0;    int tmp2=0;    for (int i=1; i<=4; i++)//先查找行    {        int cnt=4;//表示一行或者一列4个都是对的        bool flag[8];        memset(flag,0,sizeof(flag));        for (int j=1; j<=4; j++)        {            if (!flag[a[i][j]])            {                cnt--;//原本都是对的,这个没有出现过,所以减减                flag[a[i][j]]=1;            }        }            tmp1+=3-cnt;//不在正确位置的个数(如果cnt=0的话就是三个都不在正确位置)    }    for (int j=1; j<=4; j++)    {        int cnt=4;        int flag[8];        memset(flag,0,sizeof(flag));        for (int i=1; i<=4; i++)        {            if (!flag[a[i][j]])            {                cnt--;                flag[a[i][j]]=1;            }        }            tmp2+=3-cnt;    }    int ans=min(tmp1,tmp2);    return (ans+3)/4;//2 3 4 1 一步就可以移成正确的,8个错最理想移动两次,7个错最理想移动两次}void move_l(int i)//左移{    int t=a[i][1];    for (int j=2; j<=4; j++)    {        a[i][j-1]=a[i][j];    }    a[i][4]=t;}void move_r(int i)//右移{    int t=a[i][4];    for (int j=4; j>=2; j--)    {        a[i][j]=a[i][j-1];    }    a[i][1]=t;}void move_u(int j)//上移{    int t=a[1][j];    for (int i=2; i<=4; i++)    {        a[i-1][j]=a[i][j];    }    a[4][j]=t;}void move_d(int j)//下移{    int t=a[4][j];    for (int i=4; i>=2; i--)    {        a[i][j]=a[i-1][j];    }    a[1][j]=t;}bool IDA(int dep){    //cout<<get_h()<<endl;    if (dep+get_h()>want)        return false;    if (get_h()==0)        return true;    for (int i=1; i<=4; i++)    {        move_l(i);        if (IDA(dep+1))            return true;        move_r(i);        move_r(i);        if(IDA(dep+1))            return true;        move_l(i);    }    for (int j=1; j<=4; j++)    {        move_u(j);        if (IDA(dep+1))            return true;        move_d(j);        move_d(j);        if(IDA(dep+1))            return true;        move_u(j);    }    return false;}int main(){    int t;    scanf("%d",&t);    while (t--)    {        for (int i=1; i<=4; i++)        {            for (int j=1; j<=4; j++)            {                scanf("%d",&a[i][j]);            }        }        /*if (check_num())        {            cout<<"0"<<endl;        }*/        want=0;        while (want<=5)        {            if (IDA(0)==true)                break;            want++;        }        if (want<=5)            cout<<want<<endl;        else            cout<<"-1"<<endl;    }    return 0;}


 

0 0