Uva1631_分阶段动态规划

动态规划训练2——Uva1631

                    Locker
A password locker with N digits, each digit can be rotated to 0-9 circularly.
You can rotate 1-3 consecutive digits up or down in one step.
For examples:
567890 ! 567901 (by rotating the last 3 digits up)
000000 ! 000900 (by rotating the 4th digit down)
Given the current state and the secret password, what is the minimum amount of steps you have
to rotate the locker in order to get from current state to the secret password?
Input
Multiple (less than 50) cases, process to EOF.
For each case, two strings with equal length ( 1000) consists of only digits are given, representing
the current state and the secret password, respectively.
Output
For each case, output one integer, the minimum amount of steps from the current state to the secret
password.
Sample Input
111111 222222
896521 183995
Sample Output
2
12

 观察可知,假设A={a1,a2,a3…}是一最优的转动步骤,则显然更改A中序列的顺序不影响A的最优性。
 同时又有,假若x位置已经和password对应,那么此后不转动x位置对最优解的获得无影响:一次转动的位置个数与步骤数无关。
 由以上两点,可约定如下状态:
 要获取最优解A,则我们可以先进行A中处理靠前位置的转动,当靠前位置的位置处理完成后,后续转动对其无影响,因此可以不用考虑;
 令dp[i][j][k][h]表示已经处理了i个位置,j、k、h分别表示第i+1/2/3个位置上的数字。
  由状态定义中i的连续性,规定dp[i]只能转移到dp[i+1]:
  因为若直接从i转移到i+2,情况1:i+1未完成处理,不满足连续性;
  情况2:i+1完成处理,同时又有i+2完成处理,则i+2可由i+1转移得。
  综上所述,i不能转移到i+2。
因此,根据题目条件及转移规则,转移方式易得。
初始条件dp[n]=0。

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string>
#include <string.h>
#include <math.h>
#include <stdlib.h>
using namespace std;
string s, en;
int dp[1005][15][15][15],length;
const int UP = 1, DOWN = 0,INFO=1<<29;
int dis(int i, int j, int op) {
	if (op == UP)
		return (j - i + 10) % 10;
	else return (i - j + 10) % 10;
}
int DP(int n, int i, int j, int k) {
	if (n == length) return 0;
	int &ans = dp[n][i][j][k], h = (n + 3 < length ? (s[n + 3] - '0') : 0);
	if (ans != -1) return ans; 
	ans = INFO;
		for (int p = 0, d = dis(i,en[n]-'0',UP), flag = 1; p < 2; ++p, d=10-d, flag *= -1) {
			for (int a = 0; a <= d; ++a)
				for (int b = 0; b <= a; ++b)
					ans = min(ans, DP(n + 1, (j + a * flag + 10) % 10, (k + b * flag + 10) % 10, h) + d);
		}
		return ans;
}
int main(void) {
	while (cin >> s >> en) {
		length = s.length();
		memset(dp, -1, sizeof(dp)); 
		int t[3];
		for (int i = 0; i < 3; ++i)
			t[i] = (i < length ? (s[i] - '0') : 0);
		printf("%d\n", DP(0, t[0], t[1], t[2]));					
	}
	return 0;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值