Polycarpus has a ribbon, its length is n. He wants to cut the ribbon in a way that fulfils the following two conditions:
- After the cutting each ribbon piece should have length a, b or c.
- After the cutting the number of ribbon pieces should be maximum.
Help Polycarpus and find the number of ribbon pieces after the required cutting.
The first line contains four space-separated integers n, a, b and c (1 ≤ n, a, b, c ≤ 4000) — the length of the original ribbon and the acceptable lengths of the ribbon pieces after the cutting, correspondingly. The numbers a, b and c can coincide.
Print a single number — the maximum possible number of ribbon pieces. It is guaranteed that at least one correct ribbon cutting exists.
5 5 3 2
2
7 5 5 2
2
In the first example Polycarpus can cut the ribbon in such way: the first piece has length 2, the second piece has length 3.
In the second example Polycarpus can cut the ribbon in such way: the first piece has length 5, the second piece has length 2.
题目的大致意思是输入饰带的长度n和三个需求的长度a,b和c,将饰带分成a,b或c的长度,最多能分几个。与背包问题很类似,可以做一个表格进行分析,以第一个输入为例
0 | 1 | 2 | 3 | 4 | 5 | |
5 | 0 | 0 | 0 | 0 | 0 | 1 |
3 | 0 | 0 | 0 | 1 | 0 | 1 |
2 | 0 | 0 | 1 | 1 | 0 | 2 |
只有完全分解饰带的才会记录在数据中,如果a,b和c只能用一次,中间的递归过程为
for (i = 0;i < number;i++) for (j = length;j >= 0;j--) if (length >= l[i] && val[j] < val[j - l[i]] + 1) val[j] = val[j - l[i]] + 1;
如果可以重复使用,中间的递归过程为
for (i = 0;i < 3;i++) for (j = a[i];j <= len;j++) if (val[j] < val[j - a[i]] + 1) val[j] = val[j - a[i]] + 1;
两个代码唯一区别就是从len开始还是从前面开始,从len开始当前的长度不会影响结果,从前面开始当前的长度会影响结果。
#include<iostream> using namespace std; const int INF = -999999; int main() { int len, a[5], i, j, ans, val[4003]; while (scanf("%d%d%d%d", &len, &a[0], &a[1], &a[2]) != EOF) { for (i = 1;i <= len;i++) val[i] = INF; val[0] = 0; for (i = 0;i < 3;i++) for (j = a[i];j <= len;j++) if (val[j] < val[j - a[i]] + 1) val[j] = val[j - a[i]] + 1; ans = val[len]; cout << ans << endl; } return 0; }
过渡版本为:
#include<stdio.h> #include<string.h> double ribbon(int number, int *l, int length) { int i, j, val[4003]; memset(val, 0, sizeof(val)); for (i = 0;i < number;i++) for (j = length;j >= 0;j--) if (length >= l[i] && val[j] < val[j - l[i]] + 1) val[j] = val[j - l[i]] + 1; return val[length]; } int main() { int n, len[5]; scanf("%d", &n); for (int i = 0;i < 3;i++) scanf("%d",&len[i]); int ans; ans = ribbon(3, len, n); printf("%d ",ans); return 0; }