HDU 4433 locker(DP)( UVA 1631 - Locker)

题目链接:点击打开链接

题意:有一个n位密码锁,每一位都是0~9,可以循环旋转,每次可以让1~3个相邻数字同时往上或者往下旋转一格。 输入初始状态和终止状态,问最少需要转几次。

思路: 很显然是个DP题目, 由于每次可以让相邻的1~3个数字同时旋转, 所以状态的表示上就要考虑相邻3个位置。

那么可以用d[i][a][b][c]表示当前到了第i位,第i位上当前是a,i+1位是b,i+2位是c。 那么显然必须让i位上变成目标数字了, 因为接下来就转移到i+1位了,说明前i位已经全部转到目标态了。   那么转移也就很显然了, 计算出a上转和下转的次数, 然后b、c位的数字有选择的转多少次。

细节参见代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int mod = 1000000000 + 7;
const int INF = 1000000000;
const int maxn = 1000 + 10;
int T,n,m,kase=0,d[maxn][15][15][15],vis[maxn][15][15][15];
char s1[maxn], s2[maxn];
int dp(int i, int a, int b, int c) {
    int& ans = d[i][a][b][c];
    if(i >= n) return 0;
    if(vis[i][a][b][c] == kase) return ans;
    vis[i][a][b][c] = kase;
    int t = s2[i] - '0';
    ans = INF;
    if(a < t) {
        int xia = t - a;
        for(int j=0;j<=xia;j++) {
            for(int k=0;k<=j;k++) {
                int v = (b + j)%10, u = (c + k)%10;
                ans = min(ans, dp(i+1, v, u, s1[i+3]-'0')+xia);
            }
        }
        int shang = 10 - xia;
        for(int j=0;j<=shang;j++) {
            for(int k=0;k<=j;k++) {
                int v = (b - j + 10)%10, u = (c - k + 10)%10;
                ans = min(ans, dp(i+1, v, u, s1[i+3]-'0')+shang);
            }
        }
    }
    else {
        int shang = a - t;
        for(int j=0;j<=shang;j++) {
            for(int k=0;k<=j;k++) {
                int v = (b - j + 10)%10, u = (c - k + 10)%10;
                ans = min(ans, dp(i+1, v, u, s1[i+3]-'0')+shang);
            }
        }
        int xia = 10 - shang;
        for(int j=0;j<=xia;j++) {
            for(int k=0;k<=j;k++) {
                int v = (b + j)%10, u = (c + k)%10;
                ans = min(ans, dp(i+1, v, u, s1[i+3]-'0')+xia);
            }
        }
    }
    return ans;
}
int main() {
    while(~scanf("%s%s",s1,s2)) {
        ++kase;
        n = strlen(s1);
        for(int i=n;i<=n+1;i++) {
            s1[i] = s2[i] = '0';
        }
        s1[n+4] = s2[n+4] = '\0';
        printf("%d\n",dp(0,s1[0]-'0',s1[1]-'0',s1[2]-'0'));
    }
    return 0;
}


你可能感兴趣的:(uva解题报告,HDOJ,动态规划,ACM竞赛)