uva 10795 - A Different Task (递归+状态转移)

这是一个关于解决新汉诺塔问题的算法解析,通过递归和状态转移方法找到从初始状态到达目标状态的最小步骤数。问题涉及到将n个盘子在三个柱子之间移动,且需要找到从初始配置到目标配置的最短路径。
摘要由CSDN通过智能技术生成

题目链接:uva 10795 - A Different Task


思路来源于:点击打开链接

题意:

新汉若塔问题,有n个盘子,放在3个盘子上,给你一个初始状态和一个结束状态,问你最小步数怎样到达。


思路:

递归+状态转移,直接从初态到末态好像不是那么好办,对最大的一块n,首先肯定要把他放在末态的位置上,假设开始在1号位置,要放到3号位置,那么必须先到达这个状态s:1~n-1必须都从大到小放在2上面,然后放n,然后将1~n-1转移到末态,由对称性,也即可以变为末态转移到状态s,那么处理起来就可以统一了。

现在要解决怎样将一个状态转移到s(1~k全部放到一个盘子c上面),要放k,那么必须先有一个相似的状态s0,:1~k-1放到一个盘子,然后转移k,然后将1~k-1再放到k上面(原始的汉若塔问题,步数为2^(1<<(k-1)) ),可以看出解决s0和解决s是一个问题,这就得到了状态转移方程了,可以递归了。

函数 f (P,i,c),表示已知个盘子的初始柱面编号数组为P,把1到i移动到盘子c的步数,

答案就是f(st,k-1,6-st[k]-ed[k])+f(ed,k-1,6-st[k]-ed[k])+1;

然后是状态转移:计算f(P,i,c),若p[i]=c,则f(P,i,c)=f(P,i-1,c);否则需要把前i-1个盘子挪到中转盘去,将盘子i移到柱子c去,做后把前i-1个盘子从中转盘移到柱子c。


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define maxn 1005
#define MAXN 50005
#define mod 1000000009
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll;
using namespace std;

ll n,m,ans,cnt,tot,flag;
ll st[65],ed[65];

ll f(ll p[],ll k,ll to)
{
    if(k==0) return 0;
    if(p[k]==to) return f(p,k-1,to);
    else return f(p,k-1,6-to-p[k])+(1LL<<(k-1));
}
int main()
{
    ll i,j,t,test=0;
    while(scanf("%lld",&n),n)
    {
        for(i=1;i<=n;i++)
        {
            scanf("%lld",&st[i]);
        }
        for(i=1;i<=n;i++)
        {
            scanf("%lld",&ed[i]);
        }
        t=n;
        while(t>0&&st[t]==ed[t]) t--;
        if(t) ans=f(st,t-1,6-st[t]-ed[t])+f(ed,t-1,6-st[t]-ed[t])+1;
        else ans=0;
        printf("Case %lld: %lld\n",++test,ans);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值