Knapsack I
Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)
SubmitStatus
Problem Description
给出N个数a[1]....a[N],对于任意两个数(a[i],a[j]),保证a[i] % a[j] == 0 || a[j] % a[i] == 0,再给出一个数M,问这些数能否取出若干个来,使得其和为M
Input
多组数据,每组数组首先输入N,然后接下来有N个数a[1] ... a[N],然后输入M,含义如题目描述
1 <= N <= 24, 1 <= a[i],M <= 10000000
Output
每组数据,输出一行,如果可以组成M,输出"YES",否则输出"NO".
Sample Input
4 1 1 1 1 3 3 1 3 9 11
Sample Output
YES NO
直接贪心。就是现实生活中的找零钱,将输入从大到小排序, for(int i = 1; i <= n; i ++)
if(m >= a[i]) m -= a[i];
if(!m) YES; else NO
证明:不妨设存在合法方案 m = c1 + c2 + .. ck(c1 <= c2 <= ... <= ck)
假设你现在要用一个更大的数 X 去取代部分数
求出最小的 i,使得 c1 + c2 + ... + ci >= X,c1 + c2 + ... + c[i - 1] < X
尝试去掉 c1,如果 c2 + ... + ci >= X,最后剩下的串为 cj + ... + ci >= X,且 c[j + 1] + .. + ci < X,(否则继续去掉 cj)
如果 cj > X,那么 X 一定不能被替换了。
否则,因为 cj + 1 % cj = 0.. c[i] % c[i - 1] == 0,且 X >= c[j], X % c[j] = 0
设 cj + .. + ci = k1 * cj X = k2 * cj, cj + 1 + .. + ci = k3 * cj
k1 >= k2 > k3,
所以 k2 >= k3 + 1 因为 k1 - k3 == 1,只差一个 cj
所以 k2 = k1,因此可以直接用 X 替换掉 cj + .. + ci
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <algorithm> 4 #include <string.h> 5 using namespace std; 6 7 int main() 8 { 9 int n,m,i,j,a[30]; 10 while(scanf("%d",&n)!=EOF) 11 { 12 for(i=0;i<n;i++)scanf("%d",&a[i]); 13 scanf("%d",&m); 14 sort(a,a+n); 15 for(i=n-1;i>=0;i--) 16 { 17 if(m>=a[i]) 18 m-=a[i]; 19 } 20 if(m) 21 printf("NO "); 22 else printf("YES "); 23 } 24 25 }