编程之美 - 烙饼问题
2015-12-31 22:27
274 查看
把一摞烙饼按大的在下,小的在上拍好,一只手一次只能抓住上面的几张饼,把它们上下颠倒个个。反复几次后把饼排好。
问把饼排好需要的最小的次数。
问题:是看看把饼排好需要的最小次数。
找最优解的问题,可以想到用穷举法。
用递归的方式去遍历所有的翻转方式。然后找到最小的值。
可以先把最上面的两张翻一下,把次数加一,看看是不是达到要求了,如果没有的话再已经翻转过的基础上再继续递归。当顺序排好了,这是一个退出条件。
当然,书中做了优化,对当前饼的顺序做了评估,看看还有多少张饼处于不相邻的位置,给出一个评估值,如果当前已经执行的翻转次数+未来还需要翻转的次数 > 2(n-1)这是需要的最大的翻转次数时,也就可以直接退出了。
程序中可以关注一下 FindSwapCount的返回值,如果能优化其中算法,使其返回值尽量的大(当然要合理),这样就能大幅的减少递归的次数。
例如测试时饼大小的顺序是 {3,1,2},这个最少要翻两次。当前的程序需要查找 79次,如果将FindSwapCount的返回值变成2倍,这样需要查找
51次。
如果用{5,1,2,4,3}进行测试, 375289:39057,这个就比较明显了。
问把饼排好需要的最小的次数。
问题:是看看把饼排好需要的最小次数。
找最优解的问题,可以想到用穷举法。
用递归的方式去遍历所有的翻转方式。然后找到最小的值。
可以先把最上面的两张翻一下,把次数加一,看看是不是达到要求了,如果没有的话再已经翻转过的基础上再继续递归。当顺序排好了,这是一个退出条件。
当然,书中做了优化,对当前饼的顺序做了评估,看看还有多少张饼处于不相邻的位置,给出一个评估值,如果当前已经执行的翻转次数+未来还需要翻转的次数 > 2(n-1)这是需要的最大的翻转次数时,也就可以直接退出了。
程序中可以关注一下 FindSwapCount的返回值,如果能优化其中算法,使其返回值尽量的大(当然要合理),这样就能大幅的减少递归的次数。
例如测试时饼大小的顺序是 {3,1,2},这个最少要翻两次。当前的程序需要查找 79次,如果将FindSwapCount的返回值变成2倍,这样需要查找
51次。
如果用{5,1,2,4,3}进行测试, 375289:39057,这个就比较明显了。
#include <iostream> using namespace std; int nMax = 0; int nSearchTime = 0; void Print(int *pData, int nLen) { int i = 0; for (i = 0; i < nLen; i++) cout << pData[i] << " "; cout << endl; } void Swap(int *pData, int nStart, int nEnd) { int nTemp = 0; while (nStart < nEnd) { nTemp = pData[nStart]; pData[nStart] = pData[nEnd]; pData[nEnd] = nTemp; nStart++; nEnd--; } } int FindSwapCount(int* pData, int nLen) { int n = 0, i = 0; for (i = 1; i < nLen; i++) { if ((pData[i] - pData[i-1] > 1) || (pData[i] - pData[i-1] < -1)) { n++; } } return n; } bool IsOk(int *pData, int nLen) { int i = 0; for (i = 1; i < nLen; i++) { if (pData[i] < pData[i-1]) return false; } return true; } void Search(int nStep, int* pData, int nLen) { int i = 0; int nEsti = 0; nSearchTime++; nEsti = FindSwapCount(pData, nLen); if (nStep + nEsti > 2*nLen) return; if (IsOk(pData, nLen)) { if (nStep < nMax) { nMax = nStep; cout << nMax << endl; } return; } for (i = 1; i < nLen; i++) { Swap(pData, 0, i); Search(nStep+1, pData, nLen); Swap(pData, 0, i); } } void main() { int value = 0; //int test[10] = {3,1,2,6,5,4,9,8,7,0}; //int nLen = 10; //int test[5] = {5,1,2,4,3}; //int nLen = 5; int test[3] = {3,1,2}; int nLen = 3; Print(test, nLen); nMax = nLen * 2; Search(0, test, nLen); cout << nMax << " search times: "<< nSearchTime <<endl; //Print(test, nLen); cin >> value; }
相关文章推荐
- java学习之方法重载
- python语法总结
- python中元组的常用方法
- python中查找excel某一列的重复数据 剔除之后打印
- Python修改Excel数据的实例代码
- python往某一行行尾追增内容
- python使用mysql数据库
- python学习(一)pycharm安装配置篇
- 如何将DJANGO轻量级化
- 分页
- Java事务处理
- C语言isalnum()函数:判断字符是否为英文字母或数字
- QT线程2
- QT线程
- DICOM:dcm4che开源项目导入Eclipse编译错误问题解决方案
- GTK编程
- django乱码问题
- phpunit学习 3:
- java复制文件的4种方式
- UNIX环境高级编程——进程(二)