題目
給定n個不同大小的數字,每種數字個個,判斷是否可以從這些數字中選出若干數是的它們的和恰好爲K。
樣例輸入
3
3 5 8
3 2 2
17
這個樣例輸入的意思是一共有三種數字,分別是3、5、8,每個數字的個數分別是3、2、2.
即從3個3、2個5、2個8中是否能找出一個組合,其和爲17?
樣例輸出
Yes
3個3和1個8的和就是17,所以輸出Yes;反之輸出No。
算法
典型的動態規劃就能夠求解。
表示前i個數字(號)是否能選出若干和爲K。
初始化爲,,1代表Yes,0代表No。從前0個數中(也就是沒有數)能選出和爲0的數,但不能選出和爲非零的數。
就是所有的值進行或運算(如果有一個爲1就爲1)。
遞推式直接用代碼表示:
for(int i = 0;i < n;i++){
for(int j = 0;j <= K;j++){
for(int k = 0;k <= m[i] && k * a[i] <= k;k++){
dp[i+1][j] = dp[i][j-k*a[i]];
if(dp[i+1][j] == 1)break;
}
}
}
代碼
#include<stdio.h>
#define maxn 105
#define maxK 100005
int main(){
int n, K;
int a[maxn], m[maxn];
int dp[maxn][maxK]; // 嚴謹來講應該是maxn+1和MaxK+1,但我將maxn和maxK稍微定大了一點,所以沒關係
while(scanf("%d", &n)==1){
for(int i = 0;i < n;i++){
scanf("%d", &a[i]);
}
for(int i = 0;i < n;i++){
scanf("%d", &m[i]);
}
scanf("%d", &K);
// 初始化dp
for(int j = 1;j <= K;j++){
dp[0][j] = 0;
}
dp[0][0] = 1;
for(int i = 0;i < n;i++){
for(int j = 0;j <= K;j++){
for(int k = 0;k <= m[i] && k * a[i] <= k;k++){
dp[i+1][j] = dp[i][j-k*a[i]];
if(dp[i+1][j] == 1)break;
}
}
}
printf("%d\n", dp[n][K]);
}
return 0;
}