题目链接:https://vjudge.net/problem/Gym-100451B

 

解题思路:

原来的汉诺塔移动公式是(2^n)-1,那么如果我们把每两个大小相等的看成一个,相当于移动一个花费变成了2,在不考虑两个的上下顺序的情况下移动移动次数就是2*((2^n)-1) = 2^(n+1) - 2

现在的问题是要考虑相同大小的两块最终顺序问题。

用g[i]表示移动前2*i块的最小步数,r[i]表示移动前2*I块但是最后两块的顺序是和要求的颠倒的最小步数。

已知原来第i层是1 2模式的,那么如果要变成2 1模式那么g[i] = r[i-1] + 2 + (2^i) - 2,r[i-1]表示已经将前2*(i-1)层移出去了,2表示

1 2变成2 1需要的步数,将两块绑定直接移到另一个杆子上就可以了,后面就是前2*(i-1)层再移到第i层上面的步数,因为第i-1层只再移到一次,所以需要时颠倒了,而前面移到步数是偶数,所以跟原来一样就行。

r[i] = g[i-1] + 4 + 2^(i+1) - 4,既然是颠倒那么就是1 2最后还是1 2,那么不就可以看成1 2移动两次,前2*(i-1)层也要移动两次,所以这次只要g[i-1]就可以了,所以步数要乘2,2^(i+1) - 4就是2*(i-1)层搬了两次的步数,4就是1 2搬两次的步数。

如果没有大数就很简单:

#include<bits/stdc++.h> 
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int mx = 2e3 + 10;
int a[mx],n,p[mx];
int g[mx],r[mx];
int main()
{
	scanf("%d",&n);
	p[0] = 1;
	for(int i=1;i<mx;i++) p[i] = p[i-1]*2;
	for(int i=1;i<=2*n;i++) scanf("%d",a+2*n+1-i);
	if(a[2]>a[1]) g[1] = 3,r[1] = 2;
	else g[1] = 2,r[1] = 3;
	for(int i=2;i<=n;i++){
		if(a[i*2]>a[2*i-1]){
			g[i] = g[i-1] + p[i+1];
			r[i] = r[i-1] + p[i];
		}else{
			g[i] = r[i-1] + p[i];
			r[i] = g[i-1] + p[i+1];
		}
	}
	printf("%d\n",g[n]);
    return 0;
}

加了大数:

#include<bits/stdc++.h> 
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int mx = 2e3 + 10;
int a[2*mx],n,p[mx][mx],siz[mx];
int g[mx],r[mx],sizg,sizr;
int add(int *r,int *t,int cnt2)
{
	int c = 0,i = 0;
	while(i<cnt2||r[i]+t[i]+c!=0){
		r[i] += t[i] + c;
		c = r[i] / 10000;
		r[i] = r[i] % 10000;
		i++;
	}
	return i;	
}
int main()
{
	scanf("%d",&n);
	p[0][0] = siz[0] = 1;
	sizg = sizr = 1;
	for(int i=1;i<mx;i++){
		int c = 0;
		siz[i] = siz[i-1];
		for(int j=0;j<siz[i-1];j++)
		{
			int v = c + 2 * p[i-1][j];
			p[i][j] = v % 10000;
			c = v / 10000;
		}
		if(c) p[i][siz[i]++] = c;
	}
	for(int i=1;i<=2*n;i++) scanf("%d",a+2*n+1-i);
	if(a[2]>a[1]) g[0] = 3,r[0] = 2;
	else g[0] = 2,r[0] = 3;
	int *x = g,*y = r;
	for(int i=2;i<=n;i++){
		if(a[i*2]>a[2*i-1]){
			//g[i] = g[i-1] + p[i+1];
			sizg = add(x,p[i+1],siz[i+1]);
			sizr = add(y,p[i],siz[i]);
			//r[i] = r[i-1] + p[i];
		}else{
			swap(x,y);
			//g[i] = r[i-1] + p[i];
			sizg = add(x,p[i],siz[i]);
			sizr = add(y,p[i+1],siz[i+1]);
			//r[i] = g[i-1] + p[i+1];
		}
	}
	printf("%d",x[sizg-1]);
	for(int i=sizg-2;i>=0;i--) printf("%04d",x[i]);
	puts("");
    return 0;
}