111111 222222 896521 183995
2 12
题目:
给出两个串,每次可以选择连续的1-3个数字,进行同时加1或者同时减1,问最少经过多少次操作,将一个串转变为另外一个串。
思路:
dp[i][j][k]表示 前i个已经完全匹配,而这时候,第i+1个已经加了j,第i+2位已经加了k
转移分为两步,枚举加,枚举减
怎么由dp[i]转移到dp[i+1]呢?
dp[i]表示i位置已经调整好了。我们考虑调整i+1位置的情况。能够改变i位置的状态的方法有三种。
1.将i+1位置单独改变。
2.将i+1,i+2位置同时改变。
3.将i+1,i+2,i+3位置同时改变。
所以对于每一次改变。如果第i+1位改变了a,第i+2位改变了b,第i+3位改变了c,那么必定存在a>=b>=c。
因为三种改变方式有三个能改变i+1。两个能改变i+2。一个改变i+3。
详细见代码:
#include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> using namespace std; const int maxn=1010; char s1[maxn],s2[maxn]; int dp[maxn][10][10]; int main() { int i,j,k,x,y,t,len,up,dw; while(~scanf("%s%s",s1,s2)) { len=strlen(s1); memset(dp,0x3f,sizeof dp); dp[0][0][0]=0; for(i=0; i<len; i++) { for(j=0; j<10; j++) { up=(s2[i]-s1[i]-j+20)%10;//调整第i+1位需往上加的步数 dw=(10-up)%10;//需往下减往下减 for(k=0; k<10; k++) { for(x=0; x<=up; x++)//枚举i+2位可以加的值 { t=(k+x)%10;//i+1位调整好后i+2位已经加的值 for(y=0; y<=x; y++)//枚举i+3位可以加的值 dp[i+1][t][y]=min(dp[i+1][t][y],dp[i][j][k]+up); } for(x=0; x<=dw; x++)//枚举i+2位可以减的值 { t=(k-x+10)%10;//i+1位调整好后i+2位已经加的值 for(y=0; y<=x; y++)//枚举i+3位可以减的值 dp[i+1][t][(10-y)%10]=min(dp[i+1][t][(10-y)%10],dp[i][j][k]+dw); } } } } printf("%d\n",dp[len][0][0]); } }