要从初始状态移动到目标状态,需要建立参考状态,然后根据移动的可逆性,只需将两个状态移动到参考状态的和加起来即可;
首先,最大编号在两个状态中位置相同,则没必要移动,移动反而不够成最优解,若最优解中需移动该盘子,那么在最优解中去掉该盘子来回移动的两部依然构成解,与最优解的性质矛盾;所以只需找最大的那个不同位置的盘子,才是必须需要移动的,记为k
假设将k从1移动到2,那么必须将前k-1个盘子移动到3,然后将它移动到2,该状态即参考状态;
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <vector> #include <map> using namespace std; typedef long long LL; const int maxn = 61; LL mi[maxn]; int n,start[maxn],finish[maxn]; LL f(int* p,int i,int final){ if(i==0) return 0; if(p[i]==final){ return f(p,i-1,final); } else { return f(p,i-1,6-final-p[i])+mi[i-1]; } } int main() { int kase=1; mi[0] = 1; for(int i=1;i<=60;i++) mi[i]=mi[i-1]*2; while(scanf("%d",&n)==1 && n){ for(int i=1;i<=n;i++) scanf("%d",&start[i]); for(int i=1;i<=n;i++) scanf("%d",&finish[i]); int k=-1; for(int i=n;i>=1;i--){ if(start[i]!=finish[i]){ k = i; break; } } if(k==-1){ printf("Case %d: 0\n",kase++); continue; } LL res = f(start,k-1,6-start[k]-finish[k]); res+=f(finish,k-1,6-start[k]-finish[k])+1; printf("Case %d: %lld\n",kase++,res); } return 0; }