hiho1233 Boxes 记忆化搜索

来源:互联网 发布:网络不可用是怎么回事 编辑:程序博客网 时间:2024/06/07 21:06

题目链接:

hiho1233




题意:

有一个类似汉诺塔的游戏,共有n个柱子和n个大小不同的盘子

每个盘子可以移动到相邻的柱子上去,同时盘子可以叠加,但要求小的盘子放在大的盘子上面

问从当前状态到目标状态(n个盘子从小到大依次排列在n个柱子上)所需要移动的最小次数




解题思路:

首先要离散化(1~n)

最小步数------bfs

多个起点,固定终点---------------预处理,反向bfs,同时进行记忆化搜索

然后就是最关键的问题:如何在搜索中记录每一个状态(hash)

既然一根柱子可以放多个盘子,那就不能按每个位置的盘子编号叠加来hash

我们可以通过每个盘子所在的位置叠加hash,最多7个盘子即8^7可保存所有状态


代码:

#include<iostream>#include<cstdio>#include<cstring>#include<queue>#include<algorithm>#define maxn 10005000using namespace std;int dp[maxn];int pos[10],dig[10];void bfs(int x){    queue<int>q;    int head,temp,t,state=0;    dig[x]=1;    for(int i=x-1;i>=1;i--)        dig[i]=dig[i+1]*8;    for(int i=1;i<=x;i++)        state=state*8+i;    q.push(state);    dp[state]=0;    while(!q.empty())    {        t=head=q.front();        q.pop();        memset(pos,0,sizeof(pos));        for(int i=x;i>=1;i--,t/=8)            pos[t%8]=i;                            for(int i=1;i<=x;i++)        {            if(pos[i]==0)                continue;            if(i>1&&(pos[i]<pos[i-1]||!pos[i-1])){                temp=head-dig[pos[i]];                if(dp[temp]==-1)                {                    dp[temp]=dp[head]+1;                    q.push(temp);                }            }            if(i<x&&(pos[i]<pos[i+1]||!pos[i+1])){                temp=head+dig[pos[i]];                if(dp[temp]==-1)                {                    dp[temp]=dp[head]+1;                    q.push(temp);                }            }        }    }}void init(){    memset(dp,-1,sizeof(dp));    for(int i=1;i<=7;i++)        bfs(i);}int main(){    init();    int T,n,st;    int v[10],loc[10500];    scanf("%d",&T);    while(T--)    {        scanf("%d",&n);        for(int i=1;i<=n;i++){            scanf("%d",&v[i]);            loc[v[i]]=i;        }        st=0;        sort(v+1,v+1+n);        for(int i=1;i<=n;i++)            st=st*8+loc[v[i]];        printf("%d\n",dp[st]);    }    return 0;}


0 0
原创粉丝点击