HDU 汉诺塔一类问题 1997 2175 2184 2511

这类汉诺塔问题,都是根据汉诺塔的递归结构而来。

hanoi(A,B,C,n) {//把A柱上n个盘子通过B柱移向C柱
    hanoi(A,C,B,n-1);//首先把A柱上的n-1个盘子通过C柱移动B柱上
    A->C; //把A柱剩下的一个盘子从A柱移到C柱
    hanoi(B,A,C,n-1);//再把B柱上的n-1个盘子通过A柱移到C柱上
}

HDU 2175

题意:求第 m 步移动的是哪一个盘子。

思路:如果 m==2n1 显然是第n个盘子,因为 hanoi(A,C,B,n1) ;需要的是 2n11 的步数,如果 m>2n1 就进入 hanoi(B,A,C,n1) 的循环,如果 m<2n1 就进入 hanoi(A,C,B,n1) 的循环

http://acm.hdu.edu.cn/showproblem.php?pid=2175

/*********************************************
    Problem : HDU 2175
    Author  : NMfloat
    InkTime (c) NM . All Rights Reserved .
********************************************/

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define rep(i,a,b)  for(int i = a ; i <= b ; i ++)
#define rrep(i,a,b) for(int i = b ; i >= a ; i --)
#define repE(p,u) for(Edge * p = G[u].first ; p ; p = p -> next)
#define cls(a,x)   memset(a,x,sizeof(a))
#define eps 1e-8

using namespace std;

const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e5;
const int MAXE = 2e5;

typedef long long LL;

int T,n,k;
LL m;
LL base[65];

void input() {
    scanf("%d %d",&n,&m);   
}

void solve() {
    LL ans ;
    ans = ((LL)1<<62-1)*2+1;
    base[1] = 1;
    rep(i,2,63) {
        base[i] = base[i-1] * 2;
    }
    LL pos = base[n];
    if(pos == m) printf("%d\n",n);
    else rrep(i,1,n-1) {
        if(pos == m) {break;}
        else if(pos < m) pos += base[i];
        else pos -= base[i];

        if(pos == m) printf("%d\n",i);
    }
}

int main(void) {
    //freopen("a.in","r",stdin);
    //scanf("%d",&T);
    //while(T--) {
    while(scanf("%d %I64d",&n,&m),n+m) {
        //input();
        solve();
    }
    return 0;
}

HDU 2511

题意:和上题几乎一样的题意,加了一个条件,这个盘子在第 m 步是从哪个柱子走到哪个柱子的。

思路:和上题的想法一致, m==2n1 很明显是 A>C ,需要注意的是在进入 hanoi(A,C,B,n1) 的时候,是 swap(B,C) ,进入 hanoi(B,A,C,n1) swap(A,B)

http://acm.hdu.edu.cn/showproblem.php?pid=2511

/*********************************************
    Problem : HDU 2511
    Author  : NMfloat
    InkTime (c) NM . All Rights Reserved .
********************************************/

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define rep(i,a,b)  for(int i = a ; i <= b ; i ++)
#define rrep(i,a,b) for(int i = b ; i >= a ; i --)
#define repE(p,u) for(Edge * p = G[u].first ; p ; p = p -> next)
#define cls(a,x)   memset(a,x,sizeof(a))
#define eps 1e-8

using namespace std;

const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e5;
const int MAXE = 2e5;

typedef long long LL;

int T,n,k;
LL m;
LL base[65];

void input() {
    scanf("%d %I64d",&n,&m);   
}

void solve() {
    base[1] = 1;
    rep(i,2,63) {
        base[i] = base[i-1] * 2;
    }
    int start = 1 , pass = 2, end = 3;
    LL pos = base[n];
    if(pos == m) printf("%d %d %d\n",n,start,end);
    else rrep(i,1,n-1) {
        if(pos == m) {break;}
        else if(pos < m) { pos += base[i]; swap(start,pass);}
        else { pos -= base[i]; swap(pass,end);}

        if(pos == m) printf("%d %d %d\n",i,start,end);
    }
}

int main(void) {
    //freopen("a.in","r",stdin);
    scanf("%d",&T);
    while(T--) {
    //while(scanf("%d %I64d",&n,&m),n+m) {
        input();
        solve();
    }
    return 0;
}

HDU 2184

题意:求出 m 这个时刻汉诺塔是什么样子的。

思路:任然和上面类似,for()每循环一次就可以找到一个盘子的位置。

http://acm.hdu.edu.cn/showproblem.php?pid=2184

/*********************************************
    Problem : HDU 2184
    Author  : NMfloat
    InkTime (c) NM . All Rights Reserved .
********************************************/

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define rep(i,a,b)  for(int i = a ; i <= b ; i ++)
#define rrep(i,a,b) for(int i = b ; i >= a ; i --)
#define repE(p,u) for(Edge * p = G[u].first ; p ; p = p -> next)
#define cls(a,x)   memset(a,x,sizeof(a))
#define eps 1e-8

using namespace std;

const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e5;
const int MAXE = 2e5;

typedef long long LL;

int T,n,k;
LL m;
LL base[65];
int ans[4][65];
int len[4];

void init() {
    base[1] = 1;
    rep(i,2,63) {
        base[i] = base[i-1] * 2;
    }
}

void input() {
    scanf("%d %I64d",&n,&m);   
}

void solve() {
    int start = 1 , pass = 2, end = 3;
    LL pos = base[n];

    len[1] = len[2] = len[3] = 1;

    if(m >= pos) { ans[end][len[end]] = n ; len[end] ++ ;}
    else { ans[start][len[start]] = n ; len[start] ++ ;}


    rrep(i,1,n-1) { //每下降一次确定一个数的最终位置。
        if(pos < m) { pos += base[i]; swap(start,pass);}
        else { pos -= base[i]; swap(pass,end);}

        if(m >= pos) { ans[end][len[end]] = i ; len[end] ++ ;}
        else { ans[start][len[start]] = i ; len[start] ++ ;}
    }
    rep(i,1,3){
        printf("%d",len[i]-1);
        rep(j,1,len[i]-1) {
            printf(" %d",ans[i][j]);

        }
        puts("");
    }
}

int main(void) {
    //freopen("a.in","r",stdin);
    scanf("%d",&T);
    init();
    while(T--) {
    //while(scanf("%d %I64d",&n,&m),n+m) {
        input();
        solve();
    }
    return 0;
}

HDU 1997

题意:给你一个状态,判断是不是合法的。

思路:其实发现几乎就是上一题相反的题意。其实如果这个状态是合法的,还可以找到这个状态是哪一步产生的。

http://acm.hdu.edu.cn/showproblem.php?pid=1997

/*********************************************
    Problem : HDU 1997
    Author  : NMfloat
    InkTime (c) NM . All Rights Reserved .
********************************************/

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define rep(i,a,b)  for(int i = a ; i <= b ; i ++)
#define rrep(i,a,b) for(int i = b ; i >= a ; i --)
#define repE(p,u) for(Edge * p = G[u].first ; p ; p = p -> next)
#define cls(a,x)   memset(a,x,sizeof(a))
#define eps 1e-8

using namespace std;

const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e5;
const int MAXE = 2e5;

typedef long long LL;

int T,n,m,k;
int loct[65];

void input() {
    scanf("%d",&n);
    rep(i,1,3) {
        scanf("%d",&m);
        int tmp;
        rep(j,1,m) {
            scanf("%d",&tmp);
            loct[tmp] = i;
        }
    }   
}

void solve() {
    int start = 1 , pass = 2, end = 3;
    LL pos = 0;
    int ok = 0;
    rrep(i,1,n) {
        if(loct[i] == start) swap(pass,end);
        else if(loct[i] == end) swap(start,pass);
        else  {ok = 1 ; break;}
    } 
    if(ok) puts("false");
    else puts("true");
}

int main(void) {
    //freopen("a.in","r",stdin);
    scanf("%d",&T);
    while(T--) {
    //while(scanf("%d %I64d",&n,&m),n+m) {
        input();
        solve();
    }
    return 0;
}

你可能感兴趣的:(ACM)