整数分解为指定元素的加法表示:找零钱

本文乃Siliphen原创,转载请注明出处:http://blog.csdn.net/stevenkylelee


在实际项目中遇到一个问题。有一个总数N,和一个元素集合{ e1,e2 ...},求N可以是由元素集合中的什么元素相加组成。例如:总数49,元素集合{3,7,11},有如下解:

49 = 3 + 3 + 3 + 7 + 11 + 11 + 11

49 = 3 + 3 + 3 + 3 + 3 + 3 + 3 + 3 + 3 + 11 + 11

...

 

这个问题类似于现实生活中的找零钱,在一些网络棋牌游戏的断线重连恢复场景上有应用。

 

对于这个问题本人实现了一个算法,在此分享下。

 

把一个数分解若干个相加的集合元素,可以看作是对一棵树的搜索。

从根结点开始减元素集合中的元素,某个树节点的总数被减为0,那个树节点到树根结点的路径就是一个解。

示意图如下:

 

整数分解为指定元素的加法表示:找零钱_第1张图片 

 

由于是对一棵树的搜索,可以用DFS也可以用BFS。算法步骤如下:


树节点携带2个值:

本节点表示的剩余总数

一个元素值,记录本节点由父节点减掉哪个元素生成的。


根结点的值是总数,算法初始时只有一个携带总数值的根结点,从这个根结点开始展开整棵树。


每个节点扩展子节点的规则是:

当前结点的总值减掉元素列表中的每个元素,

每次总数减去一个元素列表中的一个元素就生成一个子节点。


当一个节点的总值为0时,找到了一个解。

因为总数刚好是被元素集合中的元素减为0的,

通过这条树路径可以用一路减掉的元素加回到最初的根结点总数。


当一个节点的总值小于0时,表明这条树路径无解。

 



以上思路,我实现的程序如下(算法实现70行左右):

 

 整数分解为指定元素的加法表示:找零钱_第2张图片

 

有一些解可以认为是重复的,比如

3 + 7 + 13 + 13 + 13

7 + 3 + 13 + 13 + 13

只是3和7调换了个位置。

这是因为这2个解对应的是2条不同的树路径。

 

如果元素集合中有1的话,就一定会有解,并且有相当多个解。

因为1是万能配,和自身或者其他任何元素相加都可以达到总数。


本程序的可执行文件下载:

http://download.csdn.net/detail/stevenkylelee/9878260

 

本程序的源代码下载(C#实现):

http://download.csdn.net/detail/stevenkylelee/9878261

 

 

下面的链接是我一个朋友的实现,C++,

比较简洁,核心算法20多行。


http://codepad.org/C6v4DCgX


可去掉重复的版本

http://codepad.org/rJkeauKA

你可能感兴趣的:(C#,算法实践)