三個例子
由於最近參加公司的筆試面試,發現遇到的動態規劃問題實在是多,在這邊博客裏,我特地將一些經典的算法例子抽取出來,想必之後在遇到這種動態規劃的時候都可以找到合適的模板,進行快速解題。在實戰之中,最難把握的就是通項公式的推導,我推薦在面試中遇到此類題目,優先採用遞歸的思路求解。
例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);
}
}