题目:
小明要从A地走到B地,途中会路过若干个收费站,每经过一个收费站就要缴纳一定数量的道路券,缴纳的道路券等于走过的路程。道路券有不同的规格,在每个收费站缴纳的道路券可以是各种规格的组合,各种规格道路券的数量没有限制。给定道路券的规格,以及各收费站之间的距离,求总共有多少种缴纳道路券的方式。
例:
4种道路券,规格分别为:1, 2, 5, 10。
3个收费站,与起点之间的距离依次为:0, 5, 10。
则共有16种缴纳方式。
解释:
在第一个收费站不用缴纳;在第二个收费站要缴纳价值为5的收费券,有四种可选组合:(1, 1, 1, 1, 1), (1, 1, 1, 2), (1, 2, 2),(5);在第三个收费站也要缴纳价值为5的收费券,也是4种组合。因此,共有4×4=16种缴纳方式。
算法思路:
这实际是一个整数分解问题,只不过是需要用给定的几个整数来对一个整数进行分解。可以采用递归的方式(以5为例):
第一个因子设为1,5 - 1 = 4,接下来对 4 进行分解。
扫描二维码关注公众号,回复:
3100230 查看本文章
第一个因子设为2,5 - 2 = 3,接下来对 3 进行分解。
......
递归的终止条件是:分解完毕或者无法继续分解。
这里要注意的是,(1, 1, 1, 2) 和 (1, 2, 1, 1)是同一个分解,因此,递归的过程中,比当前因子小的因子舍弃不用。例如,已经选择的因子是(1, 2),则下一个因子只从2、5、10里选,不再选择1。
代码:
#include <vector>
#include <iostream>
using namespace std;
int couponType; // 道路券规格种类
vector<int> couponValues; // 各种规格的值
int tollNum; // 收费站数量
vector<int> tollDistance; // 各收费站与起点的距离
//
// val: 要分解的整数
// start: 从第几个coupon开始
//
int choose(int val, int start)
{
int cnt = 0;
for (int i = start; i < couponType; i++)
{
val -= couponValues[i]; // 以第i个coupon作为因子
if (val == 0) // 分解完毕
cnt++;
else if (val > 0) // 未分解完
{
cnt += choose(val, i); // 继续分解,注意第二个参数
}
val += couponValues[i]; // 还原val的值
}
return cnt;
}
void main()
{
// 输入例子
couponType = 4;
int values[] = { 1, 2, 5, 10 };
couponValues.assign(values, values + couponType);
tollNum = 3;
int dis[] = { 0, 5, 10 };
tollDistance.assign(dis, dis + tollNum);
int cnt = 1; // 缴纳方式数目
for (int i = 1; i < tollNum; i++) // 遍历每个收费站
{
int dis = tollDistance[i] - tollDistance[i - 1];
cnt *= choose(dis, 0);
}
cout << cnt<< endl;
cin.get();
}