野人与传教士(C++)

河的左岸有n个野人和n个传教士,当传教士小于野人数量,传教士就会被吃掉,有一个能载m个人的船,请问最少多少次才能将野人和传教士送到右岸?
注意点:船不会自己开,每次都需要有一个人在船上。

状态判断:

  1. 是否有那么多人可以放到船上;
  2. 船上的野人数不能多于传教士数;
  3. 当传教士/野人在岸数不为0/n时,野人和传教士的数目必须相等。
#include <iostream>
using namespace std;

//记录左岸的状态
struct State {	
    int m;   //传教士
    int c;	//野人
    int boat;	//船的位置
    int count;  //移动次数
};

int solve(int n,int m) {
	//记录每次走的方式,防止重复
	int record[11][11][2]; 
	 
	//循环队列
    State queue[5] = {0};
	int head = 0;
	int tail = 0;	

    //初始状态
	State init = { n,n,1,0 };	
	queue[tail] = init;	
	tail = (tail + 1) % 5;
	
	//开始bfs
	while (head != tail) {		
	State s = queue[head];		
	head = (head + 1) % 5;		
	cout << "传教士:" << s.m << "," << "野人:" << s.c << "," << "船的位置:" << s.boat << "," << "次数:" << s.count << endl;		
	
	//左岸没有人时返回计数
	if (s.c == 0 && s.m == 0) {			
	    return s.count;		
	}		
	if (record[s.m][s.c][s.boat] == 1) {			
	    return -1;		
	}		
	record[s.m][s.c][s.boat] = 1;		

    //在左岸时
	if (s.boat == 1) {			
	    for (int i = m; i >= 1; i--) {//上船i个人				
	        if (i > s.m + s.c)	continue; //人不够				
	        for (int j = i; j >= 0; j--) { 					
	            if (j > s.c || i - j > s.m) continue;	//人不够				
	            else if (j != i && j > i - j) continue;	//船上并非全是野人,并且野人数更多				
	            else if (s.m - (i - j) != 0 && s.m - (i - j) != n && s.m - (i - j) != s.c - j) continue; //	两岸剩下的传教士不为0也不为n,且传教士和野人数量不相等(这样两边必有一边会被野人吃)		
	            else if (record[s.m - (i - j)][s.c - j][0] == 1) continue; //状态被记录过				
	            else if (s.m - (i - j) == 0 && s.c - j == 0) return s.count + 1; //状态人数变为0,返回计数			
	            State next = { s.m - (i - j), s.c - j ,0,s.count + 1};					
	            queue[tail] = next;					
	            tail = (tail + 1) % 5;				
	        }			
        }		
    }		
	else {//在右岸时(因为目的地是右岸,所以顶多送两个人到左岸(为了将野人送过去))			
	    for (int i = 1; i <= 2; i++) {				
	        if (i > 2 * n - s.m + s.c)	continue; //人不够				
	        for (int j = i; j >= 1; j--) {					
	            if (j > n - s.c || i - j > n - s.m) continue;	//人不够
	            else if (j != i && j > i - j) continue;	//船上并非全是野人,并且野人数更多		
	            else if (n - s.m - (i - j) != 0 && s.m != 0 && n - s.m - (i - j) != n - s.c - j) continue;	//两岸剩下的传教士不为0也不为n,且传教士和野人数量不相等			
	            else if (record[s.m + (i - j)][s.c + j][1] == 1) continue; //状态被记录过				
	            State next = { s.m + (i - j), s.c + j ,1,s.count + 1 };					
	            queue[tail] = next;					
	            tail = (tail + 1) % 5;			
	        }			
	    }		
	}	
    }	
	return -1;
}

int main() {	
	int m, n;	
	cin >> n >> m;	
	cout << solve(n, m);
}```

  • 12
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

河时有雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值