只不过循环要求在循环体内解决一切问题,而我们“解决一切问题”的重任担在了另一个函数里,counter不能越权,因而不能这样直接使用循环。 接下来是判断是否为有效状态的函数,它最简单了: bool match(const Pair& pair) { return (pair.x + pair.y) == 50; } 万事俱备,可以写main: int main() { WalkThrough<Pair> sf50(Pair(0, -1), &counter, &match); while (sf50.getNextFilter()) cout << sf50.getState().x << " + " << sf50.getState().y << " = 50" << endl; return 0; } 请一定要注意,getNextFilter()中有一个"Next",也就是说,如果把状态全集中的第一个状态作为构造的参数,——本题中就是Pair(0, 0)——是可行状态的话,getNextFilter()将不会判断到,它直接判断“下一个”状态,就是Pair(0, 1)去了。为了让它能够完整地判断,我们不能让Pair(0, 0)作为第一个状态,而是作为首次运行getNextFilter()后到达的状态。于是,在构造初始状态时我们就要用“前”一个状态Pair(0, -1)作为构造参数(虽然它根本不在本题的状态全集中),以使得getNextFilter()从Pair(0, 0)开始判断。 嗯,好,在运行之前不要忘了#include <iostream>,不要忘了打开std名字空间(using namespace std;),不要忘了粘上/包含上前面的WalkThrough的完整定义……编译,运行,好,这个超级难题被我们解决了。我的编译平台是Redhat Linux 9, GNU C++ 3.2.2. 最后我们分析小结一下经过封装之后的穷举算法。首先看效率——是啦,我知道这个“和是50”超级难题所用的算法很糟糕——我是指在相同算法的前提下,使用我们封装好的穷举类进行实现时的效率损失:初始化以及一系列set/get函数基本不影响效率,主开销源自于getNextFilter()本身的调用及getNextFilter对两个用户提供函数的调用所产生的额外开销。试想如果用相同的算法,但仅用两层for来做穷举,则少了上万次的函数入栈、清栈操作。穷举法本身就不是一个高效的搜索思想,所以对内层代码的效率变化是最敏感的,这一点是我们所封装的穷举类的最大缺点。 不过总算还是有一点好处,比如,封装之后,就将设计穷举算法分解成了相对独立的设计状态类、状态跳转函数、状态判断函数三个部分,三者的耦合度相对降低。此外,这个设计的过程多少让我们又多了解了一点点基于对象编程的抽象能力,嗯,等等。噢……或许这是一个学术价值大于实用价值的设计吧,呵呵。
|
正在阅读:经验分享:闲谈C++算法封装之穷举法经验分享:闲谈C++算法封装之穷举法
2004-03-26 10:05
出处:CSDN
责任编辑:linjixiong
键盘也能翻页,试试“← →”键