您的位置:首页 > 移动开发 > IOS开发

(回溯算法)商人怎样安全过河

2007-03-07 22:29 120 查看
(回溯算法)商人怎样安全过河

(本文属原创,转载请注名作者!author:wcnpepyu)

过河问题:

有三个商人和三个仆人过河,只有一条能装下两个人的船,在河的任何一岸上,如果仆人的人数大于商人的人数,那么该岸上的商人就会有危险。你能不能找出一种安全的渡河方法呢?

过河问题是一个比较出名的问题,借解这个问题的同时,我们来讲讲回溯算法.
首先,我们来分析下问题,商人们要过河,无非就是实现从全部未过河的状态到全部过河的状态.那么,问题可以转变为这样:
左岸:商人3,仆人3=>右岸:商人3,仆人3.即要通过一定的步骤实现状态的转变。而每一个状态(每次都是指船到岸,并不包含船在水中央时的情况)包含有如下几个因素:
1.左岸商人数;
2.左岸仆人数;
3.船在哪岸,即轮到哪岸的人上船.
至于右岸的商人数和仆人数到底是多少,我们不必再记上,因为知道了左岸的人,就可以推算出右岸的人。这样分析,问题便变为:
(3,3,1)=?=>(0,0,0).其中括号描述如下:(左岸商人数,左岸仆人数,船在左岸?1:0).

接下来分析商人有危险的状态。可设一个matrix[4][4]的布尔型数组。matrix[i][j]表示i个商人,j个仆人时是否安全的信息。判断是否安全的标准为哪岸的仆人数大于商人数,这岸的商人就会有危险(当然,哪一岸商人为0时,也是没危险的).用两重循环,可很快解决问题:
for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
        {
            if(i==j||i==0||i==3);
            else matrix[i][j]=true;/*其中为真时,表示有危险.*/
        }

再来分析人可以乘船的方案:以(商人数,仆人数)来表示,很明显,乘船的方案为如下5种:{0,2},{1,1},{2,0},{0,1},{1,0}.
接着就是想算法了.一开始状态为(3,3,1),通过5种乘船方案,可转变为5种状态:(3,1,0),(2,2,0),(1,3,0),(3,2,0),(2,3,0).其中matrix[i][j]为true或者不合理或者重复状态的去掉,继续向下拓展.直到出现(0,0,0)为止.从表面上看,这样似乎并不好写。这就要用到了回溯算法.所谓回溯,就是寻找问题的解的一种可靠的方法是首先列出所有候选解,然后依次检查每一个,在检查完所有或部分候选解后,即可找到所需要的解。

回溯方法的步骤如下:
1) 定义一个解空间,它包含问题的解。
2) 用适于搜索的方式组织该空间。
3) 用深度优先法搜索该空间,利用限界函数避免移动到不可能产生解的子空间。

回溯的这个深层搜索特性,便决定了它通常要用递归来做。应用到这题,显然递归的出口就是出现(0,0,0,)状态的时候。应用回溯的时候,通常有一个要特别要注意的地方,就是深入搜索完成的时候,要记得恢复前一步的状态,以便下一状态的转变。这在下面的程序会用黑体显现出来,这一点一定要注意,笔者自己也曾多次犯此错误。
现把这个问题的全部代码附上:
#i nclude <iostream>
#i nclude <stdlib.h>
using namespace std;
bool matrix[4][4],turn;
int record[128][2],pos=1;
bool check[128];
/*判断这一状态是否在前面已经出现过*/
bool isRepeat(int x,int y,bool turn)
{
    for(int i=0;i<pos;i++)
        if(x==record[i][0]&&y==record[i][1]&&turn==check[i])
            return true;
    return false;
}
void search(int px,int py)
{
    static int goStep[5][2]={{0,2},{1,1},{2,0},{0,1},{1,0}};
    int i;
    if(px==0&&py==0)
    {
        for(i=0;i<pos;i++)
        {
            cout<<"("<<record[i][0]<<","<<record[i][1]<<
            ")<==>("<<3-record[i][0]<<","<<3-record[i][1]<<")"<<endl;
        }
        system("pause");
    }
    else if(turn==false)
    {
        for(i=0;i<5;i++)
        {
            px-=goStep[i][0];
            py-=goStep[i][1];
            if(px<0||px>3||py<0||py>3||matrix[px][py]||isRepeat(px,py,turn))
            {
                px+=goStep[i][0];
              py+=goStep[i][1];

                continue;
            }
            record[pos][0]=px,record[pos][1]=py;
            check[pos]=turn;
            pos++;
            turn=(turn==true?false:true);
            search(px,py);
            pos--;
            turn=(turn==true?false:true);
            px+=goStep[i][0];
            py+=goStep[i][1];

        }
    }
    else
    {
        for(i=0;i<5;i++)
        {
            px+=goStep[i][0];
            py+=goStep[i][1];
            if(px<0||px>3||py<0||py>3||matrix[px][py]||isRepeat(px,py,turn))
            {
                px-=goStep[i][0];
                py-=goStep[i][1];
                continue;
            }
            record[pos][0]=px,record[pos][1]=py;
            check[pos]=turn;
            pos++;
            turn=(turn==true?false:true);
            search(px,py);
            pos--;
            turn=(turn==true?false:true);
            px-=goStep[i][0];
            py-=goStep[i][1];
        }
    }
}
int main()
{
    int px=3,py=3;
    for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
        {
            if(i==j||i==0||i==3);
            else matrix[i][j]=true;
        }
    record[0][0]=record[0][1]=3;
    check[0]=true;
    search(px,py);
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息