您的位置:首页 > 其它

HDU 4433 locker (线性dp)

2014-04-21 16:31 387 查看
OJ题目:click here~~

题目分析:密码锁,给初始状态和目标状态。每次可正向或者反向旋转连续的 1 , 2 , 3 位。数字在0 --- 9 之间循环,即9+1 -> 0, 0-1 -> 9。问从初始状态到目标状态的最少旋转次数。

dp[ i ][ j ][ k ]表示前i位已经匹配了 , 第i + 1目前的数字是 j , 第 i + 2 目前的数字是k , 到目标状态需要的最少旋转次数。显然dp[ n ][ j ] [ k ] 中的最小值为要求的值,其中j 在[ 0 , 9] ,k在 [ 0 , 9];

初值为dp[ 0 ][ a[ 1] ][ a[ 2 ] ] = 0 , 因为要求最小值 , 其他置为inf 。

接下来暴力dp[ i ][ j ][ k ] , 可得到dp[ n ][ j ][ k ] 。

AC_CODE

const int inf = 1<<30;
int dp[1002][11][11];
int a[1002] , b[1002] ,steps[10][10];

int main()
{
string s1 , s2;
int i , j , k , m , l , n;
for(i = 0;i < 10;i++){
j = 1;
while((i + j)%10 != i){
steps[i][(i + j)%10] = j;
j++;
}
}
while(cin >> s1 >> s2){
n = s1.length();
for(i = 0;i < n;i++){//将字符串转化为数字
a[i+1] = s1[i] - '0';
b[i+1] = s2[i] - '0';
}
for(i = 0;i <= n;i++)
for(j = 0;j <= 9;j++)
for(k = 0;k <= 9;k++)
dp[i][j][k] = inf;
dp[0][a[1]][a[2]] = 0;//初值
for(i = 0;i < n;i++)//枚举每一位
for(j = 0;j < 10;j++)//i+1位为j
for(k = 0;k < 10;k++){//i+2位为k
if(dp[i][j][k] < inf){//如果此状态可达,则可得出下一个状态。若不可达,当然不处理。
int t = steps[j][b[i+1]];//第i+1位现在为j ,要旋转到b[i + 1]需要t步
for(l = 0;l <= t;l++)//第i+2位正向旋转l步
for(m = 0;m <= l;m++){//第i+3位正向旋转m步,显然不能超过l
dp[i+1][(k+l)%10][(a[i+3] + m)%10] = min(dp[i+1][(k+l)%10][(a[i+3] + m)%10] , dp[i][j][k] + t);
}
for(l = 0;l <= 10-t;l++)//第i+2位逆向旋转l步
for(m = 0;m <= l;m++){//第i+3位逆向旋转m步,显然不能超过l
dp[i+1][(k-l+10)%10][(a[i+3]-m+10)%10] = min(dp[i+1][(k-l+10)%10][(a[i+3]-m+10)%10] , dp[i][j][k] + 10 - t);
}
}
}
int ans = inf;
for(i = 0;i < 10;i++)
for(j = 0;j < 10;j++)
ans = min(ans , dp
[i][j]);
cout << ans << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: