这类汉诺塔问题,都是根据汉诺塔的递归结构而来。
hanoi(A,B,C,n) {
hanoi(A,C,B,n-1);
A->C;
hanoi(B,A,C,n-1);
}
HDU 2175
题意:求第
m
步移动的是哪一个盘子。
思路:如果m==2n−1显然是第n个盘子,因为
hanoi(A,C,B,n−1)
;需要的是
2n−1−1
的步数,如果
m>2n−1
就进入
hanoi(B,A,C,n−1)
的循环,如果
m<2n−1
就进入
hanoi(A,C,B,n−1)
的循环
http://acm.hdu.edu.cn/showproblem.php?pid=2175
#include <map>
#include <set>
#include <queue>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#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) {
while(scanf("%d %I64d",&n,&m),n+m) {
solve();
}
return 0;
}
HDU 2511
题意:和上题几乎一样的题意,加了一个条件,这个盘子在第
m
步是从哪个柱子走到哪个柱子的。
思路:和上题的想法一致,m==2n−1很明显是
A−>C
,需要注意的是在进入
hanoi(A,C,B,n−1)
的时候,是
swap(B,C)
,进入
hanoi(B,A,C,n−1)
是
swap(A,B)
。
http://acm.hdu.edu.cn/showproblem.php?pid=2511
#include <map>
#include <set>
#include <queue>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#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) {
scanf("%d",&T);
while(T--) {
input();
solve();
}
return 0;
}
HDU 2184
题意:求出
m
<script id="MathJax-Element-592" type="math/tex">m</script>这个时刻汉诺塔是什么样子的。
思路:任然和上面类似,for()每循环一次就可以找到一个盘子的位置。
http://acm.hdu.edu.cn/showproblem.php?pid=2184
#include <map>
#include <set>
#include <queue>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#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) {
scanf("%d",&T);
init();
while(T--) {
input();
solve();
}
return 0;
}
HDU 1997
题意:给你一个状态,判断是不是合法的。
思路:其实发现几乎就是上一题相反的题意。其实如果这个状态是合法的,还可以找到这个状态是哪一步产生的。
http://acm.hdu.edu.cn/showproblem.php?pid=1997
#include <map>
#include <set>
#include <queue>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#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) {
scanf("%d",&T);
while(T--) {
input();
solve();
}
return 0;
}