http://acm.hdu.edu.cn/showproblem.php?pid=4433
记忆化搜索+DP
ans[x][f][ff]; 表示到a的第x位时 此位加f ,x-1位 加ff 的情况下的最优解
a的x位加f后如果还不到 b[x] 然后分两种情况 一个是a的第x位不断加 直到等于b[x] 或者不断减直到等于b[x]
对于两种情况 分别枚举长度为 1 ,2 ,3的个数的情况 对下两层的影响 对下两层的影响 无论是加多少还是减多少 都可以转化为 加上一个10以内的数(因为是循环的)
然后不断递归
时间复杂度 O(N*10*10*C(12,2)) 大约10^7
代码及其注释:
#include<iostream> #include<stdio.h> #include<string.h> #include<math.h> #include<algorithm> #include<vector> #include<set> #include<queue> #include<map> #include<string> #include <iomanip> using namespace std; const int INF=0x3f3f3f3f; const int N=1005; int ans[N][12][12];//到第x位时 此位加f ,x-1位 加ff 时的最优解 char s1[N],s2[N]; int a[N],b[N]; int dp(int x,int f,int ff) { if(ans[x][f][ff]!=-1) return ans[x][f][ff]; int tmp=(a[x]+f)%10;//x位加 f 后的结果 if(x==0) { if(ff!=0)//到第0位时 -1位不能再进行加减 return (ans[x][f][ff]=INF); return (ans[x][f][ff]=min((b[x]-tmp+10)%10,(tmp-b[x]+10)%10));//否则选个最优就可 } if(tmp==b[x])//当前位已经不需要加减 return (ans[x][f][ff]=dp(x-1,ff,0)); ans[x][f][ff]=INF; int k=(b[x]-tmp+10)%10;//不断加的情况 for(int i=0;i<=k;++i) for(int j=0;j<=(k-i);++j) { int l=k-i-j; if(i+j+l==k)//枚举 长度1,2,3的个数的情况 对下两层的影响 求最优解 ans[x][f][ff]=min(ans[x][f][ff],k+dp(x-1,(ff+i+l)%10,l)); } k=(tmp-b[x]+10)%10;//不断减的情况 for(int i=0;i<=k;++i) for(int j=0;j<=(k-i);++j) { int l=k-i-j; if(i+j+l==k) ans[x][f][ff]=min(ans[x][f][ff],k+dp(x-1,(ff-i-l+10)%10,(-l+10)%10)); } return ans[x][f][ff]; } int main() { //freopen("data.txt","r",stdin); while(scanf("%s %s",s1,s2)!=EOF) { memset(ans,-1,sizeof(ans)); int n=strlen(s1); for(int i=0;i<n;++i) {a[i]=s1[i]-'0';b[i]=s2[i]-'0';} printf("%d\n",dp(n-1,0,0)); } return 0; }