编程之美 - 烙饼问题

把一摞烙饼按大的在下,小的在上拍好,一只手一次只能抓住上面的几张饼,把它们上下颠倒个个。反复几次后把饼排好。
问把饼排好需要的最小的次数。

问题:是看看把饼排好需要的最小次数。

找最优解的问题,可以想到用穷举法。
用递归的方式去遍历所有的翻转方式。然后找到最小的值。

可以先把最上面的两张翻一下,把次数加一,看看是不是达到要求了,如果没有的话再已经翻转过的基础上再继续递归。当顺序排好了,这是一个退出条件。

当然,书中做了优化,对当前饼的顺序做了评估,看看还有多少张饼处于不相邻的位置,给出一个评估值,如果当前已经执行的翻转次数+未来还需要翻转的次数 > 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;

}

你可能感兴趣的:(编程之美 - 烙饼问题)