动态规划

动态规划面试题--数字转化机

2017-09-13  本文已影响237人  jdzhangxin

最近编程题目都是DP,我把今天这个题给大家做个解释和实现。大家好好体会练习,遇到最优解问题(最小/最大)时,优先DP解法。

概念

一般求最优解通常使用DP(Dynamic Programming)。

DP主要两个要素,有三种解法。

状态和状态转化方程最关键也比较困难。状态转化方程包含边界。有时称为三要素,是把边界单独分离出来,与状态和状态转化方程并列。


题目

时间限制:(每个case)2s,空间限制:128MB
小Q从牛博士那里获得一台数字转化机,这台数字转化机必须同时输入两个整数ab,并且这台数字转化机有一个红色按钮和一个蓝色按钮。

小Q现在手中有四个整数,abAB,他希望将输入的两个整数ab变成ABa对应Ab对应B)。因为牛博士允许小Q使用数字转化机时间有限,所以,小Q希望按动按钮的次数越少越好,请你帮帮小Q吧。

100 1000 202 2002
2

分析

解决

为了使代码更加简洁地表示解决思路,中间未添加参数检查处理。

测试主函数

本题测试函数非常简单只是终端输入输出操作。

int main(){
    int a(0),b(0),A(0),B(0);
    cin >> a >> b >> A >> B;
    int res1 = transfer(a,A);
    int res2 = transfer(b,B);
    if(res1 == res2 and -1 != res1){
        cout << res1;
    }else{
        cout << -1;
    }
}

实现转换函数transfer()

int transfer(int first,int last){
    if(first == last) return 0; // 可以完成转换
    if(first > last) return -1; // 不能完成转换
    int res1 = transfer(first,last/2);
    int res2 = transfer(first,last-1);
    if(-1 == res1 and -1 == res2){
        return -1;
    }else if(-1 == res1){
        return res2+1;
    }else if(-1 == res2){
        return res1+1;
    }else{
        return min(res1,res2)+1;
    }
}

注意,转化失败的分支不能参与最小转化次数比较的。程序需要增加这些处理。

int transfer(int first,int last,int buf[]){
    if(first == last) return 0; // 可以完成转换
    if(first > last) return -1; // 不能完成转换
    if(-1 != buf[last]){
        return buf[last];
    }
    int res1 = transfer(first,last/2,buf);
    int res2 = transfer(first,last-1,buf);
    if(-1 == res1 and -1 == res2){
        return -1;
    }else if(-1 == res1){
        buf[last] = res2+1;
    }else if(-1 == res2){
        buf[last] = res1+1;
    }else{
        buf[last] = min(res1,res2)+1;
    }
    return buf[last];
}
int transfer(int first,int last){
    int buf[last+1];
    fill_n(buf,last+1,-1);
    return transfer(first,last,buf);
}

注意这里定义一个数组,数组的下标表示last,数组值表示从数字first转化到数字last最少转化次数。数组需要初始化为无效值-1,用于判断是否已经计算过。

int transfer(int first,int last){
    int buf[last+1];
    fill_n(buf,last+1,0);
    for(int i=first+1;i<=last;i++){
        if(i/2 >= first and i-1 >= first){
            buf[i] = min(buf[i/2],buf[i-1])+1;
        }else if(i/2 >= first){
            buf[i] = buf[i/2]+1;
        }else if(i-1 >= first){
            buf[i] = buf[i-1]+1;
        }else{
            buf[i] = -1;
        }
    }
    return buf[last];
}

这里数组表示含义与备忘录法一致的,虽然会有一定空间浪费,时间复杂度,已经从O(2^n)降低到O(n)

通常有时间限制的DP,优先使用表格法,备忘录法在一些情况会比表格法快,基本不使用递归法。

使用回溯法可以把表格法和备忘录法获得的存储中间值,转化成获得最优解具体的操作,例如本题中,小Q究竟是依次按了哪些按钮获得last值。有能力的童鞋,可以自己练习解决。

上一篇下一篇

猜你喜欢

热点阅读