编程解决 传教士和食人者问题

编程解决 传教士和食人者问题_第1张图片

很简单的搜索,但是其中的条件还是太多,卡了好久
ans : 解法个数
m1[],m2[] 中记录船只上的传教士和食人者方案,负数表示船由西向东航行,整数相反.例如m1[i] = -1,m2[i] = 0:向东运送一个传教士;m1[i] = 1,m2[i] = 1:向西运一个传教士一个食人者。
path : 记录每一步(船的航行方向和船上传教士和食人者)情况,由于每次都只有两个数字,所以将其压缩成一个1小于10000的10进制整数,若船向东航行则记录在千位和百位,若向西航行则记录在十位和个位。例如向东运两个食人者,则path[i]=200,向东运1个传教士,一个食人者,则path[i] =1100;向西运两个食人者,path[i]=2,向西运一个传教士一个食人者,path[i]=11.
visit 记录状态是否访问过,避免绕一圈又返回到之前已经出现过的状态,出现死循环。前四个维度分别记录左右岸的传教士和食人者数量的分布(和下面的x1,y1,x2,y2一致),最后一维表示船只航行方向,0:l2r(左到右),1:r2l(右到左)
x1/x2 :左右岸传教士人数
y1/y2 :左右岸食人者人数
lastm1,lastm2 : 上一次的船只航行时的方向和传教士,食人者人数(定义同m1[i],m2[i])
step 记录当前步数(即船航行了几次),便于记录path和区分方向,step%2==0 则下一步该向东航行,反之向西航行。

#include
using namespace std;
int ans = 0;
int m1[10] = {-2,0,-1,0,-1,1,1,0,2,0};
int m2[10] = {0,-2,0,-1,-1,1,0,1,0,2};
int path[100];
bool visit[4][4][4][4][2]; // 0 : l2r   1 : r2l
void dfs(int x1,int y1,int x2,int y2,int lastm1,int lastm2,int step)
{
    if(x1 == 0 && y1 == 0 && x2 == 3 && y2 == 3)
    {
        ans ++;
        cout << "ans" << ans << ":" << endl;
        for(int i = 1; i <= step; ++i)
        {
            if(i % 2 == 1)
            {
                cout << "step" << i << ": l2r: " << path[i]/100/10 << "个传教士," << path[i]/100%10 << "个食人者" << endl;
            }
            else
            {
                cout << "step" << i << ": r2l: " << path[i]/10 << "个传教士," << path[i]%10 << "个食人者" << endl;
            }
        }
        return ;
    }
    if(step % 2 == 0)
    {
        // l2r
        for(int i = 0; i < 5; ++i)
        {
            if((m1[i]+lastm1 == 0) && (m2[i]+lastm2 == 0))
                continue;
            if((x1+m1[i])>=0 && (x1+m1[i])<=3 && (y1+m2[i])>= 0 && (y1+m2[i])<= 3 && (x2-m1[i]) >=0 && (x2-m1[i])<=3 && (y2-m2[i]) >=0
               && (y2-m2[i])<=3
               && !visit[x1+m1[i]][y1+m2[i]][x2-m1[i]][y2-m2[i]][0]
               && ((x1+m1[i])>=(y1+m2[i]) || x1+m1[i] == 0) && ((x2-m1[i])>= (y2-m2[i]) || x2-m1[i] == 0))
            {
                visit[x1+m1[i]][y1+m2[i]][x2-m1[i]][y2-m2[i]][0] = true;
                path[step+1] = 1000*(-m1[i]) + 100*(-m2[i]);
                dfs(x1+m1[i],y1+m2[i],x2-m1[i],y2-m2[i],m1[i],m2[i],step+1);
                visit[x1+m1[i]][y1+m2[i]][x2-m1[i]][y2-m2[i]][0] = false;
            }
        }
    }
    else
    {
        // r2l
        for(int i = 5; i < 10; ++i)
        {
            if((m1[i]+lastm1 == 0) && (m2[i]+lastm2 == 0))
                continue;
            if(((x1+m1[i])>=0) && ((x1+m1[i]) <=3) && ((y1+m2[i])>= 0) && ((y1+m2[i]) <= 3) && ((x2-m1[i]) >=0)
               && ((x2-m1[i])<=3) && ((y2-m2[i]) >=0) && ((y2-m2[i])<=3)
               && !visit[x1+m1[i]][y1+m2[i]][x2-m1[i]][y2-m2[i]][1]
               && (((x1+m1[i])>=(y1+m2[i])) || (x1+m1[i] == 0)) && (((x2-m1[i])>= (y2-m2[i]))) || (x2-m1[i]==0))
            {
                visit[x1+m1[i]][y1+m2[i]][x2-m1[i]][y2-m2[i]][1] = true;
                path[step+1] = 10*m1[i] + m2[i];
                dfs(x1+m1[i],y1+m2[i],x2-m1[i],y2-m2[i],m1[i],m2[i],step+1);
                visit[x1+m1[i]][y1+m2[i]][x2-m1[i]][y2-m2[i]][1] = false;
            }
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    memset(visit,0,sizeof(visit));
    visit[3][3][0][0][0] = true;
    dfs(3,3,0,0,0,0,0);
    return 0;
}

一共有四种解法:
编程解决 传教士和食人者问题_第2张图片
编程解决 传教士和食人者问题_第3张图片

你可能感兴趣的:(AI)