Knapsack I 竟然是贪心,证明啊。。。。

本文探讨了一种特定条件下的背包问题,即所有物品价值之间存在整除关系时的解决方案。通过对输入数值进行排序并采用贪心策略,文章提供了一个简单而有效的算法实现,用于判断是否能从给定的数值集合中选取若干个数使其和等于目标值。

Knapsack I

Time Limit:  2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)
Submit Status
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

 

 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\n");
22         else printf("YES\n");
23     }
24 
25 }
View Code

 

转载于:https://www.cnblogs.com/ERKE/p/3852761.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值