意甲冠军:给定的长度可达1000数的顺序,图像password像锁。可以上下滑动,同时会0-9周期。

每个操作。最多三个数字连续操作。现在给出的起始序列和靶序列,获得操作的最小数量,从起始序列与靶序列。


花了一天的时间。我觉得是道非常难的DP。这个阶段非常好划分,对于前面完毕的password锁就不再考虑。问题的关键是这个旋转每次能够的情况非常多。

同一时候也能够发现当I位置上确定移好后,至多影响到后两位。-> dp[i][j][k] 表示当前i位移好后,i+1 为j ,  i+2为k 的次数。

这里同一时候使用一个预处理技巧,对于一个移动操作。有向上向下两种。

当将一个值转到还有一个值,up[i][j]=(j-i+10)%10;down[i][j]=(i-j+10)%10;  i->j 的方法

在dp中必定会有对于阶段的描写叙述,一般从1開始,表达每一段。这里为了求dp[n][0][0] 在最后再补上两位。

dp[0][s[0]][s[1]]=0;
刚開始0阶段,一个都未完毕的时候。即前0次移好i+1,i+2位为这种次数为0

int r=up[j][t[i-1]];//①
dp[i][(k+u)%10][(s[i+1]+v)%10]=min(...)//②


这两句话是我刚開始一直困惑的地方。

首先要明白转移方程是阶段间的转移dp[i-1][...][...]->dp[i][...][...]

这样看,配合②我们发现当dp[i-1][j][k]已知,dp[i][...][...]是将其  j转为t[i-1]。(这个是理解的关键)。这里的u,v表明的是在j转为t[i-1]过程中。后两位的改变情况枚举值。

dp[i][(k+u)%10][(s[i+1]+v)%10] 这个如今就能够理解了,对于dp[i-1]的j 如今dp[i]考虑的就是上次的K了。

另一点就是标号非常乱一会是阶段的i。一会又是起始位置.......

#include <stdio.h>
#include <string.h>
#include <map>
#include <iostream>
#define inf 0x3fffffff
const int maxn=1010;
typedef unsigned __int64 ull;
using namespace std;
char s[maxn],t[maxn];
int dp[maxn][10][10];
int up[10][10],down[10][10];
int min(int a,int b)
{
	return a<b?a:b;
}
void init()
{
	int i,j;
	for(i=0;i<10;i++)
		for(j=0;j<10;j++)
		{
			up[i][j]=(j-i+10)%10;
			down[i][j]=(i-j+10)%10;
		}
}

int main()
{
	init();
	while(~scanf("%s%s",s,t))
	{
		memset(dp,0x3f,sizeof(dp));
		int i,j,k,u,v;
		int n=strlen(s);
		s[n]=s[n+1]=t[n]=t[n+1]=0;
		for(i=0;i<n;i++)
			s[i]-='0',t[i]-='0';
		dp[0][s[0]][s[1]]=0;//除了最初的序列。其它的dp都没有合法值
		for(i=1;i<=n;i++)
		{
			for(j=0;j<10;j++)//枚举两位数字的每一位  
			{
				for(k=0;k<10;k++)
				{
					int r=up[j][t[i-1]];//从j转到t[i-1]的次数,将三位中最左边的数字向上转到目标序列须要的操作
					for(u=0;u<=r;u++)//枚举可能出现的操作
					{
						for(v=0;v<=u;v++)
							dp[i][(k+u)%10][(s[i+1]+v)%10]=min(dp[i][(k + u) % 10][(s[i+1] + v) % 10], dp[i-1][j][k] + r);  
					}
					r=down[j][t[i-1]];
					for(u=0;u<=r;u++)
						for(v=0;v<=u;v++)
							dp[i][(k-u+10)%10][(s[i+1]-v+10)%10]=min(dp[i][(k - u+10) % 10][(s[i+1] - v +10) % 10], dp[i-1][j][k] + r);
				}
			}
		}
		printf("%d\n",dp[n][0][0]);
	}




	return 0;
}