【60行以内简单实现】农夫、羊、菜和狼的故事

这篇博客介绍了如何利用深度优先搜索(DFS)解决经典的农夫过河问题。代码展示了如何通过枚举狼、羊、菜和人的位置状态,找到最少渡河次数的解决方案。虽然理论上最少渡河次数为7次,但博客作者并未展示所有可能的7次解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述:有一个农夫带一只羊、一筐菜和一只狼过河。如果没有农夫看管,则狼要吃羊,羊要吃菜。但是船很小,只够农夫带一样东西过河。问农夫该如何解此难题?

输入描述:

题目没有任何输入。

输出描述:

题目可能有种解决方法,求出步骤最少的解决方法,
按顺序输出农夫想把羊、菜、狼全部运过河需要哪几个步骤。
如果需要将羊带过河去则输出“sheep_go”。
如果需要将羊带回来则输出“sheep_come”。
如果需要将菜带过河去则输出“vegetable_go”。
如果需要将菜带回来则输出“vegetable_come”。
如果需要将狼带过河去则输出“wolf_go”。
如果需要将狼带回来则输出“wolf_come”。
如果需要空手返回则输出“nothing_come”。
如果需要空手过河则输出“nothing_go”。
每输出一种方案,输出一行“succeed”。

A - 农夫、羊、菜和狼的故事计算机保研,计算机考研国家线,计算机考研需要考哪些科目,计算机考研院校推荐,计算机考研学校排名,计算机考研科目,计算机考研,计算机考研大纲,计算机专业考研,计算机考研专业课,计算机408考研科目,计算机考研机试,软件工程考研,考研真题https://www.noobdream.com/DreamJudge/Contest/49/1457/?Problem=A

本来想找个OJ测下的,无奈找不到,只有这个OJ有这道题(也是,这个题知道答案的话七行打表就出来了,确实没啥意思)

使用DFS做,对狼羊人菜的位置状态pos进行枚举,最初置pos数组全为1,最终pos数组全为1则过河成功,且搜索中不允许出现重复的状态(否则人可以过来,过去,又过来,又过去...这样的搜索不仅没有意义,而且递归是出不来的)。由于pos数组只有4个非0即1的量,可以用四位二进制数表示,于是就有了visited数组来标志状态是否已重复,重复就过了,不继续搜了。以下是代码:

#include<iostream>
#include<vector>
#include<string>
enum object{
	MAN, SHEEP, WOLF, VEGETABLE
}; 
std::string names[4]={"nothing", "sheep", "wolf", "vegetable"};
bool visited[16]; 
std::vector<std::string> ret;
std::vector<std::string> path;
int make_idx(std::vector<int>& pos){
	return pos.at(0)+(pos.at(1)<<1)+(pos.at(2)<<2)+(pos.at(3)<<3);
}
bool check_valid(std::vector<int>& pos){
	return pos[MAN]==pos[SHEEP]||(pos[SHEEP]!=pos[WOLF]&&pos[SHEEP]!=pos[VEGETABLE]);
}
bool check_success(std::vector<int>& pos){
	return pos[SHEEP]==1&&pos[MAN]==1&&pos[WOLF]==1&&pos[VEGETABLE]==1;
}
template<typename T> void print_vec(std::vector<T>& pos){
	for(auto item:pos){
		std::cout<<item<<std::endl;
	}
}
void dfs(std::vector<int>& pos){
	if(!check_valid(pos)) return;
	if(check_success(pos)){
		if(ret.empty()||ret.size()>path.size()){
			ret.assign(path.begin(), path.end());
		}
		return;
	}
	std::string direction = pos[MAN]==1?"come":"go";
	for(int i=MAN; i<=VEGETABLE;++i){
		// man go/come
		std::vector<int> new_pos(pos);
		new_pos[MAN]=1-new_pos[MAN];
		if(i!=MAN){
			// take something
			if(new_pos[i]!=new_pos[MAN]){
				new_pos[i]=new_pos[MAN];
			}else continue;
		}
		int pos_idx=make_idx(new_pos);
		if(visited[pos_idx]) continue;
		path.push_back(names[i]+"_"+direction);
		visited[pos_idx]=true;
		dfs(new_pos);
		visited[pos_idx]=false;
		path.pop_back();
	}
}
int main(){
	std::vector<int> pos = {0,0,0,0};
	dfs(pos);
	print_vec(ret);
	return 0;	
}

理论上来说7次就是最小渡河次数,但应该是有2种7次渡河方法的,这里偷懒没写了~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值