您的位置:首页 > 其它

Locker UVA - 1631 (dp)

2017-08-17 13:43 417 查看
题目链接:点击打开链接

题目大意:给出一个密码锁的当前状态和最终状态,每一次可以将连续的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-6
using 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]));
}
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ACM dp