关闭

C++习题:野人与修道士过河问题

2764人阅读 评论(0) 收藏 举报
分类:
 
河的左岸有3个野人和3个修道士以及一条小船,修道士们想用这条小船把所有的人都运到河的右岸,但又受到以下限制:
1、修道士和野人都会划船,但船一次只能载2人;
2、在任何岸边,野人数不能超过修道士数,否则修道士将会被野人吃掉。
假定野人愿意服从任何一种过河的安排,请规划出一种确保修道士安全的过河方案。

以下是犯规情形: - 例如,对面有1个坏,船上有1好1坏,则船到对面后1好2坏,犯规。

 
#include <stdio.h>

struct record
{
	int a,b,c,d;
};

record history[1000];
int    count = 0;

// 保存记录
void Push(int a, int b, int c, int d)
{
	record* r = &history[count];
	r->a = a;
	r->b = b;
	r->c = c;
	r->d = d;
	count ++;
}

// 追溯
void Pop()
{
	count --;
}

// 压入一个相对值,表示每次运人的数目
//(2,0)(0,2)(1,1)(1,0),(0,1)
//(-2,0)(0,-2)(-1,-1)(-1,0),(0,-1)
void Push(int x1, int x2)
{
	record* r = &history[count-1];
	int a = r->a;
	int b = r->b;
	int c = r->c;
	int d = r->d;
	Push(a-x1, b-x2, c+x1, d+x2);
}

// 当前状态是否曾经出现过,避免无限循环
bool IsDuplicate()
{
	record* last = &history[count-1];

	// 取最后一条
	for(int i=0; i<count-1; i++)
	{
		record* r = &history[i];
		if(last->a == r->a && last->b == r->b)
		{
			if(i%2 == (count-1)%2)
				return true;
		}
	}
	return false;
}

// 辅助打印函数
void PrintHistory()
{
	printf("\n---------------\n");
	for(int i=0; i<count; i++)
	{
		record* r = & history[i];

		if(i%2) printf(">> ");
		else    printf("<< ");
		printf("%d %d %d %d\n", r->a, r->b, r->c, r->d);
	}
}

// count: 已经存在的记录数
bool TryPlan()
{
	// PrintHistory();

	// 取得最后一条记录
	record* r = &history[count-1];
	int a = r->a;
	int b = r->b;
	int c = r->c;
	int d = r->d;

	// 已经到达最终状态
	if(a==0 && b==0 && c==3 && d==3)
		return true;

	// 是否有效
	if(a<0 || b<0 || c<0 || d<0) 
	{
		printf("invalid.\n");
		return false;
	}

	// 检查此状态是否安全
	if( a>0 && a<b) 
	{
		printf("not safe.\n");
		return false;
	}
	if( c>0 && c<d) 
	{
		printf("not safe.\n");
		return false;
	}

	// 检查此状态是否已经出现过
	if( IsDuplicate()) 
	{
		printf("dup\n");
		return false;
	}

	printf("Continued.\n");

	if(count % 2 != 0) 
	{
		// 偶数: 从本岸到对岸,过去
		Push(0,2);
		if(TryPlan()) return true;
		Pop();

		Push(2,0);
		if(TryPlan()) return true;
		Pop();

		Push(1,1);
		if(TryPlan()) return true;
		Pop(); // 退回一层

		Push(1,0);
		if(TryPlan()) return true;
		Pop(); // 退回一层

		Push(0,1);
		if(TryPlan()) return true;
		Pop();

		return false;
	}
	else
	{
		// 奇数: 从对岸对本岸,回来
		Push(-2,0);
		if(TryPlan()) return true;
		Pop(); // 退回一层

		Push(0,-2);
		if(TryPlan()) return true;
		Pop(); // 退回一层

		Push(-1,-1);
		if(TryPlan()) return true;
		Pop(); // 退回一层

		Push(-1,0);
		if(TryPlan()) return true;
		Pop(); // 退回一层

		Push(0,-1);
		if(TryPlan()) return true;
		Pop();

		return false;

	}
}

int main()
{
	Push(3,3,0,0);
	bool ret = TryPlan();
	if(! ret)
	{
		printf("没有解决方案");
	}
	else
	{
		for(int i=0; i<count; i++)
		{
			record* r = & history[i];
			printf("%d %d %d %d\n", r->a, r->b, r->c, r->d);
		}
	}

	return 0;

}
 

答案:

3 3 0 0

3 1 0 2

3 2 0 1

3 0 0 3

3 1 0 2

1 1 2 2

2 2 1 1

0 2 3 1

0 3 3 0

0 1 3 2

1 1 2 2

0 0 3 3

 

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:350111次
    • 积分:4471
    • 等级:
    • 排名:第6922名
    • 原创:108篇
    • 转载:0篇
    • 译文:0篇
    • 评论:62条
    新书推荐
    《C/C++学习指南》,一本C/C++语法教材,与同类教材/图书相比,本书由业内人士撰写,由浅入深、循序渐近的讲解所有语法问题,并结合了工程实践进行分析。它的理念是让编程变得简单,让人一看就懂。它的目标是成为大中专院校、培训班、从业人员和爱好者的人手一本的必备教材。
    最新评论