Locker UVA

来源:互联网 发布:淘宝网首页登陆电脑版 编辑:程序博客网 时间:2024/06/05 14:43

题目链接:点击打开链接

题目大意:给出一个密码锁的当前状态和最终状态,每一次可以将连续的1~3个向上或者向下转动,问最少要转几次

题目思路:很容易知道是dp题但是还是比较难想出状态转移和定义状态的,如果是第一次写这种类型,首先定义状态dp[i][j][k],代表第i位,第i位为j,i+1位为k,还需转动几次,

为什么要这么定义呢,首先我们知道对于每一位来说肯定是要转到和目标状态相同的,那么我们从最左边的开始考虑,对于当前考虑的这一位,肯定是要变为目标状态的,所以我们去转动他,使其和目标状态一样,当我们转动这一位的时候会给下一位和下两位带来影响,这个时候我们去枚举下一位和下两位所能变动的位数,产生一个新的状态,这里要注意一下第二位转动的次数要小于等于第一位,这样子就产生了状态转移和决策了。

ac代码:

#include<cstdio>#include<algorithm>#include<cstring>#include<cstring>#include<iostream>#include<sstream>#include<cmath>#include<vector>#define LL long long#define INF 0x3f3f3f3f#define eps 1e-6using namespace std;const int maxn = 1e7+6;int a[1050];int b[1050];char s1[1050];char s2[1050];int n;int dp[1050][11][11];int dfs(int now,int a1,int a2){    int &ret = dp[now][a1][a2];    if(ret!=-1)        return ret;    if(now>n)       return  ret = 0;    ret = INF;    int sumup;    if(a1>b[now]){        sumup = 9-a1+b[now]+1;    }    else{        sumup = b[now]-a1;    }    for(int i = 0;i<=sumup;i++){        for(int j = 0;j<=i;j++){            ret = min(ret,dfs(now+1,(a2+i)%10,(a[now+2]+j)%10)+sumup);        }    }    int sumdn;    if(a1>=b[now]){        sumdn = a1-b[now];    }    else{        sumdn = a1+1+9-b[now];    }    for(int i = 0;i<=sumdn;i++){        for(int j = 0;j<=i;j++){            ret = min(ret,dfs(now+1,(a2-i+10)%10,(a[now+2]-j+10)%10)+sumdn);        }    }     return ret;}int main(){    while(~scanf("%s%s",s1+1,s2+1))    {        memset(a,0,sizeof(a));        memset(b,0,sizeof(b));        n = strlen(s1+1);        memset(dp,-1,sizeof(dp));        for(int i = 1;i<=n;i++){            a[i] = s1[i]-'0';            b[i] = s2[i]-'0';        }        printf("%d\n",dfs(1,a[1],a[2]));    }}