三个例子
由于最近参加公司的笔试面试,发现遇到的动态规划问题实在是多,在这边博客里,我特地将一些经典的算法例子抽取出来,想必之后在遇到这种动态规划的时候都可以找到合适的模板,进行快速解题。在实战之中,最难把握的就是通项公式的推导,我推荐在面试中遇到此类题目,优先采用递归的思路求解。
例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商品,数量为{2,3,1},商品组合bom1{2,1,1},bom2{1,1,0},bom3{0,1,1}
对以上订单匹配给定商品组合,得到的可能匹配结果为: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);
}
}