面试中的动态规划问题

6 篇文章 0 订阅

三个例子

由于最近参加公司的笔试面试,发现遇到的动态规划问题实在是多,在这边博客里,我特地将一些经典的算法例子抽取出来,想必之后在遇到这种动态规划的时候都可以找到合适的模板,进行快速解题。在实战之中,最难把握的就是通项公式的推导,我推荐在面试中遇到此类题目,优先采用递归的思路求解。

例1:

n(10>=n>=1)种商品A1,A2,...,An,每种商品数量分别为a1,a2,...,an个,记做{a1,a2,...,an}(ak>0)。热门组合商品会进行预包装。假设这n个商品有m(9>=m>=1)个商品组合,每个组合bomk包含A1,A2,...,An的数量分别为{b1,b2,...,bn}(bk>=0,至少存在一个bk>0)

举例如下:

订单包含A,B,C商品,数量为{231},商品组合bom1{211},bom2{110},bom3{011}

对以上订单匹配给定商品组合,得到的可能匹配结果为:res1.匹配到组合1一套,剩余B商品;res2.匹配到组合2两套,组合3一套,不剩商品;

现要求订单的最优匹配,最优匹配的原则为:1.匹配组合后,剩余商品种类数越少越好;2.在剩余商品种类数相同的情况下,匹配到的组合种类数越少越好;

例如上面例子,我们认为res2优于res1。



现需要编写程序,输入格式为:

n,m

a1,a2,...,an

bom1,b11,b12,...,b1n

bom2,b21,b22,...,b2n

....

bomm,bm1,bm2,...,bmn



输入数据的格式说明(数据间使用英文逗号分隔):

第一行数据:n个商品,m个预包方案

第二行数据:商品1个数,商品2个数,。。。,商品n个数

第三行数据:bom1,商品1个数,商品2个数,。。。,商品n个数

第n-1行数据:。。。。

第n行数据:bomn,商品1个数,商品2个数,。。。,商品n个数



针对输入数据找出最优匹配,输出最优匹配的组合及套数,比如针对上面的例子输出:

match result:

bom2*2,bom3*1

注:输出结果有多个时可以乱序
import copy
input_data1=input().split(',')
m = [int(x) for x in input_data1][0]
n = [int(x) for x in input_data1][1]
input_data2 = input().split(",")
limit = [int(x) for x in input_data2]
boms = []
for i in range(n):
    input_temp = input().split(',')
    boms.append([int(x) for x in input_temp])

best_combo = [0]*n
best_num = [0]*m
current_bag = [0]*n
bag_num = [0]*m

def bag(current_bag,bag_num):
    global best_combo
    global best_num
    temp_num = -1
    for bom in boms:
        new_current_bag = copy.deepcopy(current_bag)
        new_bag_num = copy.deepcopy(bag_num)
        temp_num += 1
        temp_flag = True
        for i in range(n):
            if current_bag[i] + bom[i] > limit[i]:  #判断n件商品是否能全部放入背包
                temp_flag = False
        if temp_flag:              #如果能够全部放入背包则全部放入背包如一个物品可以被加入
            new_bag_num[temp_num] += 1
            for j in range(n):
                new_current_bag[j] += bom[j]
            if better_than(new_current_bag,new_bag_num,best_combo,best_num):
                best_combo = current_bag
                best_num = bag_num
            bag(new_current_bag,new_bag_num)


def better_than(current_bag,bag_num,best_combo,best_num):
    if (sum([(limit[i]-current_bag[i]) for i in range(n)]) < sum([(limit[i]-best_combo[i]) for i in range(n)])):  #如果剩余的总量小,则最好的背包是现在的背包
        return True
    elif sum([(limit[i]-current_bag[i]) for i in range(n)]) == sum([(limit[i]-best_combo[i]) for i in range(n)]): #如果剩余的总量相等,比较种类数量
        if sum(bag_num) < sum(best_num):
            return True

bag(current_bag,bag_num)

例2

找零钱问题:

有一个数组changes,changes中所有的值都为正数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,对于一个给定值x,请设计一个高效算法,计算组成这个值的方案数。

给定一个int数组changes,代表所以零钱,同时给定它的大小n,另外给定一个正整数x,请返回组成x的方案数,保证n小于等于100且x小于等于10000。

测试样例:
[5,10,25,1],4,15
返回:6
测试样例:
[5,10,25,1],4,0
返回:1


//这道题目有两种实现方式,分别是递归以及非递归,这里优先写出递归的模式
public static int solusion(int[] array,int begin,int end,int target){
    //返回条件
    if (target == 0){
        return 1;
    }
    if(begin > end){
        return 0;
    }
    int count = 0;
    int times = 0;
    for(times*array[begin] <= target){
        count+=solustion(array,begin+1,end,target-times*array[begin]);
        times++;
    }
    return count;
}
//以下代码是迭代实现的案例:
public static int solusion(int[] array,int m,int n){
//初始化工作
    int[] dp = new int[n+1];
    dp[0]=1;
    for(int charge:array){
        for(int i=0;i+charge <= target;i++){
            dp[i+charge] += dp[i]
            }
        }
    return dp[n]


    }

例3

全排列问题:

输入一个字符列表,输出他的全排列(改:排列中不得出现重复的排列)

package Test;

import java.util.Arrays;

public class Test4 {


    public static void allpossible(int[] array,int begin) {
        int temp;
        int end = array.length;
        if(begin==end) {
            System.out.println(Arrays.toString(array));
            return;
        }
        else

        for(int x=begin;x<end;++x) {
            //swap index to all data;
            temp = array[begin];
            array[begin] = array[x];
            array[x] = temp;
            allpossible(array, begin+1);
            temp = array[begin];
            array[begin] = array[x];
            array[x] = temp;
        }
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int [] test = {3,2,1};
        allpossible(test, 0);

    }

}
package Test;

import java.util.Arrays;
import java.util.HashSet;

public class Test5 {


    public static void allpossible(int[] array,int begin) {
        HashSet<int[]> testSet = new HashSet<int[]>();
        int temp;
        int end = array.length;
        if(begin==end) {
            if(!testSet.contains(array)) {
                testSet.add(array);
                System.out.println(Arrays.toString(array));
            }
            return;
        }
        else

        for(int x=begin;x<end;++x) {
            //swap index to all data;
            temp = array[begin];
            array[begin] = array[x];
            array[x] = temp;
            allpossible(array, begin+1);
            temp = array[begin];
            array[begin] = array[x];
            array[x] = temp;
        }
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int [] test = {3,2,2,1};
        allpossible(test, 0);

    }

}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值