zoj 2338 The Towers of Hanoi Revisited

来源:互联网 发布:淘宝客买家平台 编辑:程序博客网 时间:2024/05/29 09:30

  还是太naive了,在知道经典汉诺塔的情况下,居然很久没想出来。其实多根棍子和三根是一个原理。n个盘子,m根棍子的最优解,一定是把一部分盘子(假设为x)先移到某个中间棍子上,也就是先解决子问题(x,m),然后把剩下的n-x个盘子通过剩下的m-1根棍子用最优方案转移,即子问题(n-x,m-1),最后把中间棍子上的那x个盘子移过去,即子问题(x,m)。这样可以用dp来求解。

#include <iostream>    #include <stdio.h>    #include <cmath>    #include <algorithm>    #include <string>    #include <memory.h>    #include <vector>    #include <queue>    #include <stack>  using namespace std;#define ll unsigned long long ll dp[77][77];int num[77][77];ll fun(int n,int m){    if(dp[n][m]){        return dp[n][m];    }    if(n==0){        return 0;    }else if(n==1){        return 1;    }else if(m==2){        return n;    }else if(m==3){        num[n][m] = n-1;        dp[n][m] = fun(n-1,3)*2+1;        return dp[n][m];    }    ll res = (~(0ULL))>>1;;    for(int i=1;i<n;i++){        ll tmp = fun(i,m)*2+fun(n-i,m-1);        if(tmp<=res){            res = tmp;            num[n][m] = i;        }    }    dp[n][m] = res;    return res;}stack<int> pegs[77];void move(int from,int to){    if(pegs[to].size()){        printf("move %d from %d to %d atop %d\n",pegs[from].top(),from,to,pegs[to].top());        pegs[to].push( pegs[from].top() );        pegs[from].pop();    }else{        printf("move %d from %d to %d\n",pegs[from].top(),from,to);        pegs[to].push( pegs[from].top() );        pegs[from].pop();    }}int M;void solve(int n,int m,int from,int to){    if(n==1){        move(from,to);        return;    }    if(m==2){        while(n--){            move(from,to);        }        return;    }    stack<int> where;    stack<int> how;    int curn = n;    int curm = m;    for(int i=1;i<=M;i++){        if(i==from || i==to)continue;        if(pegs[i].size() && pegs[from].top()>pegs[i].top())continue;         int tmp = num[curn][curm];        if(tmp==0){            break;        }        if(curn==1)break;        solve(tmp,curm,from,i);        where.push(i);        how.push(tmp);        curn-=tmp;        curm--;    }    curm++;    move(from,to);    while(where.size()){        solve(how.top(),curm,where.top(),to);        how.pop();        where.pop();        curm++;    }}int main(){    for(int i=1;i<=65;i++){        for(int j=4;j<=65;j++){            fun(i,j);        }    }    int t;    cin>>t;    while(t--){        int n,m;        cin>>n>>m;        M = m;        for(int i=n;i>=1;i--){            pegs[1].push(i);        }        cout<<fun(n,m)<<endl;               solve(n,m,1,m);        while(pegs[m].size()){            pegs[m].pop();        }    }    return 0;} 
0 0
原创粉丝点击