超级码侬

学的技术太多了,输送一点给大家^^

C++习题:野人与修道士过河问题
 
河的左岸有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

 

阅读更多
个人分类: C/C++语言
想对作者说点什么? 我来说一句

修道士野人问题

2011年12月30日 3KB 下载

没有更多推荐了,返回首页

不良信息举报

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

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭