zoj 2338 The Towers of Hanoi Revisited

  还是太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;
} 

你可能感兴趣的:(dp)