传教士和野人问题

forever_life 2010-07-16 12:22:20
问题描述:有三个牧师和三个野人过河,只有一条能装下两个人的船,在河的任何一方或者船上,如果野人的人数大于牧师的人数,那么牧师就会有危险。你能不能找出一种安全的渡河方法呢?这个问题可以扩展为N1个牧师和N2野人,而船一次可以装下M个人的情况。
要求:(1)给出可能的方法总数,并描述每种方法的具体实现过程;
(2)当输入N1,N2,M的值时,输出程序的运行结果。
...全文
1417 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
tragedyxd 2012-11-12
  • 打赏
  • 举报
回复
引用 20 楼 Javkburd 的回复:
引用 18 楼 tragedyxd 的回复:就是约瑟夫问题。 C/C++ code1234567891011121314151617181920212223242526272829303132333435363738394041424344454647#include <stdio.h>#define MAX 255 int main(){ int i,j,r,t……
思路是差不多的,你把存活的人数改成传教士的人数就可以了
JackBurd 2012-11-11
  • 打赏
  • 举报
回复
引用 18 楼 tragedyxd 的回复:
就是约瑟夫问题。 C/C++ code1234567891011121314151617181920212223242526272829303132333435363738394041424344454647#include <stdio.h>#define MAX 255 int main(){ int i,j,r,temp; int people[MAX……
怎么是约瑟夫问题了?求解释。。。
JackBurd 2012-11-11
  • 打赏
  • 举报
回复
广搜写的,效率应该还可以。
#include<stdio.h>
#include<math.h>

#define MAX 1000  //M和C最大分别可取1000,自己可随便定义

struct Queue
{
	int m[2]; //存储左右两岸传教士的数目
	int c[2]; //存储左右两岸野人的数目
	int bank; //0, 1分别代表右岸和左岸
	int pre;
}q[MAX*MAX];

int mark[2][MAX][MAX]; //计算右岸野人和传教士的数目,用于判重(有两种状态,分别是船处于右岸和左岸时右岸野人和传教士的数目)

bool Safe(int m[], int c[])
{
	return !((c[0] > m[0] && m[0]) || (c[1] > m[1] && m[1]));
}

void Print(int idx[], int len)
{
	char str[2][5] = {"过河", "回去"};
	int m, c;
	int cnt = 0;
	
	for(int i = len-1, bank = 0; i > 0; i --, bank = !bank)
	{
		m = abs(q[idx[i]].m[0] - q[idx[i-1]].m[0]);
		c = abs(q[idx[i]].c[0] - q[idx[i-1]].c[0]);
		
		printf("[%d]: ", ++cnt);
		if(m) printf("%d个传教士", m);
		if(m && c) printf("和");
        if(c) printf("%d个野人", c);
		printf("%s\n", str[bank]);
	}
}

void main()
{
	Queue cur, next;
	int M, C, K;
    int m, c, bank;
	int head, tail;
	int idx[MAX];
	bool find = false;
	
	scanf("%d%d%d", &M, &C, &K);
	
	head = tail = -1;
	mark[0][M][C] = 1; 
	
	q[++tail].m[0] = M;  //初始状态入队
	q[tail].m[1] = 0;
	q[tail].c[0] = C;
	q[tail].c[1] = 0;
	q[tail].bank = 0;
	q[tail].pre = -1;
	
	while(head <= tail)
	{
		cur = q[++head];
		bank = cur.bank;
		
		if(bank && cur.m[1] == M && cur.c[1] == C)
		{
			find = true;

			for(int i = head, len = 0; i >= 0; i = q[i].pre)
			{
				idx[len++] = i;  //记录解中队列元素的下标,便于打印路径
			}
			
			Print(idx, len);   break;
		}
		
		for(int i = 1; i<=K && i<=M+C; i ++)
		{
			for(int j = 0; j <= i; j ++)
			{
				next.m[bank] = cur.m[bank] - j;
				next.m[!bank] = M - next.m[bank];
				next.c[bank] = cur.c[bank] - (i-j);
				next.c[!bank] = C - next.c[bank];
				
				m = next.m[0], c = next.c[0];
				
				if(next.m[!bank] <= M && next.c[!bank] <= C 
			        && Safe(next.m, next.c) && !mark[!bank][m][c])
				{
					next.bank = !bank;
					next.pre = head;
					
					q[++tail] = next;
					mark[!bank][m][c] = 1;
				}
			}
		}
	}

	if(!find)  printf("不能顺利到达对岸\n");
}
tragedyxd 2012-11-11
  • 打赏
  • 举报
回复
就是约瑟夫问题。

#include <stdio.h>
#define MAX 255

int main()
{
int i,j,r,temp;
int people[MAX] = {0};
int n,deadnumber;
printf("Please input People number AND Deadnumber.\n");
while (scanf("%d%d",&n,&deadnumber) != EOF)
{
r = 0;

for (i = 0;i <n;i++)
{
people[i] = i + 1;
}
i = 0;
temp = 0;
while (r < n - 2) //control people
{
if (people[i] != 0)
{
temp++;
}
if (temp == deadnumber) //dead_line
{
people[i] = 0;
r++;
temp = 0;
}
i++;
if (i == n)
{
i = 0;
}
}
for (i = 0;i <= n;i++)
{
if (people[i] > 0)
{
printf("%d\n",people[i]);
}
}
}
}
smsgreenlife 2012-11-11
  • 打赏
  • 举报
回复
没看懂题目,什么叫“如果野的人数”?
JackBurd 2012-11-10
  • 打赏
  • 举报
回复
广搜,类似于农夫过河,只是限制条件不一样。。。
honemay 2010-07-16
  • 打赏
  • 举报
回复
作业题?
c_song 2010-07-16
  • 打赏
  • 举报
回复
能运行不?试试

兄台 这东东是数据结构 搜索 tree
c_song 2010-07-16
  • 打赏
  • 举报
回复
#include <stdio.h>
#include<malloc.h>
#include <stdlib.h>

typedef struct
{
int xds; /*xiudaoshi*/
int yr; /*yeren*/
int cw; /*船工*/
}DataType;

DataType fa[5000];

typedef struct node
{
DataType data;
struct node *son;
struct node *bro;
struct node *par;
struct node *next;
}Ltable;

void print(Ltable *q,Ltable *p);
void work(Ltable *p,int n,int c);
void insertbro(Ltable *head,DataType x);
void Ltableinit(Ltable **head);

int main(void)
{
Ltable *p;
DataType tem;
int n,c;

Ltableinit(&p); /*初始化邻接表;*/
while (1)
{
printf("请输入修道士与野人的人数n:\n");
scanf("%d",&n);
if (n==0)
break;
printf("请输入船可容纳的人数c:\n");
scanf("%d",&c);
tem.xds=n;
tem.yr=n;
tem.cw=1;
insertson(p, tem); /*将初始状态作为头结点的孩子结点;*/
work(p,n,c); /*进行广度搜索;*/
}
return 0;
}
void Ltableinit(Ltable **head) /*初始化邻接表的操作*/
{
if((*head=(Ltable *)malloc(sizeof (Ltable)))==NULL); /*动态分配空间*/
{
puts("Malloc error!");
exit(1);
}
(*head)->son=NULL;
(*head)->bro=NULL;
(*head)->par=NULL;
(*head)->next=NULL;
}

void insertbro(Ltable *head,DataType x) /*在邻接表中插入兄弟结点的操作,所有的兄弟结点都指向他们右边的结点;*/
{
Ltable *q,*s;
q=(Ltable *)malloc(sizeof (Ltable));
s=head->son;
q->data=x;
while (s->bro!=NULL)
s=s->bro;
s->bro=q;
s->next=q;
q->next=NULL;
q->bro=NULL;
q->par=head;
q->son=NULL;
}

void work(Ltable *p,int n,int c)
{
Ltable *q,*t;
DataType tem;
int i,flag,flag1,g=0,j,count=0;
q=p->son;
while (q!=NULL)
{
flag=0;
j=findfa(q->data,c);
for (i=0;i<j;i++)
{
tem.xds=q->data.xds-fa[i].xds;
tem.yr=q->data.yr-fa[i].yr;
tem.cw=1-q->data.cw;
t=q;
if (jiancha (tem,n))
{
flag1=1;
while (t!=p)
{
if(tem.xds==t->data.xds&&tem.yr==t->data.yr&&tem.cw==t->data.cw)
{
flag1=0;
break;
}
t=t->par;
}
if(flag1==1)
{
if (flag==0)
{
insertson(q, tem);
flag=1;
}
else
insertbro(q,tem);
if (tem.xds==0&&tem.yr==0&&tem.cw==0)
{
print(q,p);
count++;
}
}
}
}
q=q->next;
}
if (count==0)
printf("无法成功渡河,修道士好郁闷!\n");
else
printf("有%d种渡河方式。\n",count);
}


void print(Ltable *q,Ltable *p) /*打印安全渡河的过程*/
{
DataType a[100];
int i=1;
a[0].cw=0;
a[0].xds=0;
a[0].yr=0;
while (q!=p)
{
a[i++]=q->data;
q=q->par;
}
while ((--i)>-1)
{
printf("( %d %d %d )",a[i].xds,a[i].yr,a[i].cw);
if (!(a[i].xds==0&&a[i].yr==0&&a[i].cw==0))
{
if (a[i].cw==1)
printf(" --> ( %d %d ) --> ( %d %d 0 )\n",a[i].xds-a[i-1].xds,a[i].yr-a[i-1].yr,a[i-1].xds,a[i-1].yr);
else
printf(" <-- ( %d %d ) <-- ( %d %d 1 )\n",(a[i].xds-a[i-1].xds)*(-1),(-1)*(a[i].yr-a[i-1].yr),a[i-1].xds,a[i-1].yr);
}
else printf("\n");
}
printf("渡河成功!\n");
}
forever_life 2010-07-16
  • 打赏
  • 举报
回复
拜求程序...
zuiyuezhou888 2010-07-16
  • 打赏
  • 举报
回复
mark 面试的时候碰到过
forever_life 2010-07-16
  • 打赏
  • 举报
回复
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
typedef struct
{
int xds; //xiudaoshi
int yr; //yeren
int cw; //chuanwei
}DataType;
DataType fa[50000];
typedef struct node
{
DataType data;
struct node *son;
struct node *bro;
struct node *par;
struct node *next;
}Ltable;
void Ltableinit(Ltable **head) //初始化邻接表的操作
{
*head=(Ltable *)malloc(sizeof (Ltable)); //动态分配空间
(*head)->son=NULL;
(*head)->bro=NULL;
(*head)->par=NULL;
(*head)->next=NULL;
}
void insertson(Ltable *head, DataType x) //在邻接表中插入儿子结点的操作
{
Ltable *q,*s;
q=(Ltable *)malloc(sizeof (Ltable));
q->data=x;
head->son=q;
s=head;
while (s->next!=NULL)
s=s->next;
q->par=head;
q->son=NULL;
q->bro=NULL;
s->next=q;
q->next=NULL;
}
void insertbro(Ltable *head,DataType x) //在邻接表中插入兄弟结点的操作,所有的兄弟结点都指向他们右边的结点;
{
Ltable *q,*s;
q=(Ltable *)malloc(sizeof (Ltable));
s=head->son;
q->data=x;
while (s->bro!=NULL)
s=s->bro;
s->bro=q;
s->next=q;
q->next=NULL;
q->bro=NULL;
q->par=head;
q->son=NULL;
}

int findfa(DataType x,int n) //生成在船上修道士仍安全的几种情况;
{
int i=0,a,b,t=0;
if(x.cw)
{
a=0;b=n-a;
while (a+b>=1)
{
t++;
while (b>=0)
{

fa[i].xds=a;
fa[i].yr=b;
i++;
a++;
b--;
}
a=0;
b=n-a-t;
}
}
else
{
a=1;b=0;t=0;
while (a+b<=n)
{
t++;
while (a>=0)
{
fa[i].xds=a*(-1);
fa[i].yr=b*(-1);
i++;
a--;
b++;
}
a=fa[0].xds*(-1)+t;
b=0;
}
}
return i;
}

int jiancha(DataType x,int n) //安全性检测,检查当前情况下,修道士是否安全
{
if ((x.xds>=x.yr||x.xds==0)&&((n-x.xds)>=(n-x.yr)||x.xds==n)&&x.xds>=0&&x.xds<=n&&x.yr>=0&&x.yr<=n)
return 1;
else
return 0;
}

void print(Ltable *q,Ltable *p) //打印安全渡河的过程
{
DataType a[100];
int i=1;
a[0].cw=0;
a[0].xds=0;
a[0].yr=0;
while (q!=p)
{
a[i++]=q->data;
q=q->par;
}
while ((--i)>-1)
{
printf("( %d %d %d )",a[i].xds,a[i].yr,a[i].cw);
if (!(a[i].xds==0&&a[i].yr==0&&a[i].cw==0))
{if (a[i].cw==1)
printf(" --> ( %d %d ) --> ( %d %d 0 )\n",a[i].xds-a[i-1].xds,a[i].yr-a[i-1].yr,a[i-1].xds,a[i-1].yr);
else printf(" <-- ( %d %d ) <-- ( %d %d 1 )\n",(a[i].xds-a[i-1].xds)*(-1),(-1)*(a[i].yr-a[i-1].yr),a[i-1].xds,a[i-1].yr);
}
else printf("\n");
}
printf("渡河成功!\n");
}

void work(Ltable *p,int n,int c)
{
Ltable *q,*t;
DataType tem;
int i,flag,flag1,g=0,j,count=0;
q=p->son;
while (q!=NULL)
{
flag=0;
j=findfa(q->data,c);
for (i=0;i<j;i++)
{
tem.xds=q->data.xds-fa[i].xds;
tem.yr=q->data.yr-fa[i].yr;
tem.cw=1-q->data.cw;
t=q;
if (jiancha (tem,n))
{
flag1=1;
while (t!=p)
{
if(tem.xds==t->data.xds&&tem.yr==t->data.yr&&tem.cw==t->data.cw)
{
flag1=0;
break;
}
t=t->par;
}
if(flag1==1)
{
if (flag==0)
{
insertson(q, tem);
flag=1;
}
else
insertbro(q,tem);
if (tem.xds==0&&tem.yr==0&&tem.cw==0)
{
print(q,p);
count++;
}
}
}
}
q=q->next;
}
if (count==0)
printf("无法成功渡河,修道士好郁闷!\n");
else
printf("有%d种渡河方式。\n",count);
}
int main()
{
Ltable *p;
DataType tem;
Ltableinit(&p); //初始化邻接表;
int n,c;
while (1)
{
printf("请输入修道士与野人的人数n:\n");
scanf("%d",&n);
if (n==0)
break;
printf("请输入船可容纳的人数c:\n");
scanf("%d",&c);
tem.xds=n;
tem.yr=n;
tem.cw=1;
insertson(p, tem); //将初始状态作为头结点的孩子结点;
work(p,n,c); //进行广度搜索;
}
return 1;
}
望能改一下printf(" --> ( %d %d ) --> ( %d %d 0 )\n",a[i].xds-a[i-1].xds,a[i].yr-a[i-1].yr,a[i-1].xds,a[i-1].yr);
这句话有问题 您可以运行一下
c_song 2010-07-16
  • 打赏
  • 举报
回复
贴上看看
forever_life 2010-07-16
  • 打赏
  • 举报
回复
就是没辙了,网上倒是有。不过有问题,你能帮忙改一下吗?
c_song 2010-07-16
  • 打赏
  • 举报
回复
哦,你这是数据结构的题

我没学过数据结构,我想想,看不一定能实现的了

你既然学过自己也想想
forever_life 2010-07-16
  • 打赏
  • 举报
回复
人人都可以独立开船..
c_song 2010-07-16
  • 打赏
  • 举报
回复
野人可以自己开船么?
forever_life 2010-07-16
  • 打赏
  • 举报
回复
您能给一个可运行的程序吗?拜托了...
c_song 2010-07-16
  • 打赏
  • 举报
回复
大概应该用队列能解决吧
三个结构 每个结构里 都存有牧师与野人的数量
一个判断函数if牧师小于野人continue 之类的
返回波尔型数据,
真就计数
假就下一个
关于河岸 船上 对岸 应该是三个循环嵌套

大体就这样了吧

forever_life 2010-07-16
  • 打赏
  • 举报
回复
是作业题啊 急求.....下午就交.....
加载更多回复(1)

69,370

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧