循环链表之约瑟夫环问题

来源:互联网 发布:战国立志传姬武将数据 编辑:程序博客网 时间:2024/05/21 17:33


不带密码的约瑟夫环问题:
约瑟夫环(约瑟夫问题)是一个数学的应用问题:
已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。
从编号为1的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数
,数到k的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。
通常解决这类问题时我们把编号从0~n-1,最后[1]  结果+1即为原问题的解。

方法一:利用单向循环链表,模拟出列。并输出每次出列人的编号
这里编号直接是从1-n 不用再+1
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int num;
struct node *next;
}cnode;
void joseph(int n,int k);
int main()
{
joseph(10,3);
return 0;
}
void joseph(int n,int k)//n个人,数到k出列
{
//先创建一个单向循环链表
cnode *head,*pre,*p;
cnode *temp;
int i;
head=NULL;
for(i=1;i<=n;i++)
{
p=(cnode *)malloc(sizeof(cnode));
p->num=i;
if(head==NULL)
head=p;
else
pre->next=p;
pre=p;
}
p->next=head;


//开始模拟出列
temp=head;//如果是从编号m的人开始报数,在这里将temp指向开始报数地址就行
while(temp->next != temp)//删除到只剩一个节点条件
{
//找到要出列的节点位置
for(i=1;i<k;i++)
{
pre=temp;
temp=temp->next;
}
//删除找到的节点
pre->next=temp->next;
printf("out person is %d\n",temp->num);
free(temp);


//重新定义下一个开始数数的人
temp=pre->next;
}
printf("last one is %d\n",temp->num);


}


方法二:利用数学方法解答
//一群人围成圆桌编号1,2-n,数到k的出列,求出列顺序和最后留下的人的编号


#include<stdio.h>
int Joseph_math(int n,int k);
int outperson_number(int n,int k,int i);
int main()
{
int i;
int num;


for(i=1;i<=10;i++)
{
num=outperson_number(10,3,i);
printf("number %d times out is %d\n",i,num+1);//注意结果+1
}

return 0;
}
//n个人设编号是0,1-(n-1),最后求得的编号+1就是要求的编号
//这个函数只能输出最后一个人的编号
int Joseph_math(int n,int k)
{
int i;
int out=0;
for(i=2;i<=n;i++)
{
out=(out+k)%i;
}
return out;
}


//n个人,数1-k出列,i表示第i次出列人的编号
//这个函数可以输出每次出列人的编号
int outperson_number(int n,int k,int i)
{
if(i==1)
return (k-1)%n;
else
return (outperson_number(n-1,k,i-1)+k)%n;


}


//////////////////////////////////////////////////////////
带密码的约瑟夫环问题
问题的描述唯一的不同之处就是每个人都会持有一个密码,这个密码用来设置k,
也就说一个人出局以后,按他所拥有的密码作为k来进行淘汰。
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int num;
int code;
struct node *next;
}cnode;
void joseph(int n,int a[]);
int main()
{
int a[10]={2,3,1,4,3,2,4,1,3,1};//下一次出列人数的数code
// int a[10]={3,3,3,3,3,3,3,3,3,3};
joseph(10,a);
return 0;
}
void joseph(int n,int a[])//n个人,数到k出列
{
//先创建一个单向循环链表
cnode *head,*pre,*p;
cnode *temp;
int i;
int k;
head=NULL;
 
for(i=1;i<=n;i++)
{
p=(cnode *)malloc(sizeof(cnode));
p->num=i;
p->code=a[i-1];
if(head==NULL)
head=p;
else
pre->next=p;
pre=p;
}
p->next=head;


//开始模拟出列
temp=head;

k=temp->code;
while(temp->next != temp)//删除到只剩一个节点条件
{
//找到要出列的节点位置
 
for(i=1;i<k;i++)
{
pre=temp;
temp=temp->next;
}
//删除找到的节点
k=temp->code;
pre->next=temp->next;
printf("out person is %d\n",temp->num);
free(temp);


//重新定义下一个开始数数的人
temp=pre->next;
}
printf("last one is %d\n",temp->num);


}







0 0
原创粉丝点击