绕圈转点数问题

题目
救济金发放

n(n≤20)个人站成一圈,逆时针,编号为1~n。有两个官员,A从1开始逆时针数,B从n开始顺时针数。在每一轮中,官员A数k个就停下来,官员B数m个就停下来(有可能两个官员停在同一个人上)。被官员选中的人(1个或2个)离开队伍去领取救济金。输入n,k,m,输出每轮里被选中的人的编号(若有2个人,先输出被A选中的)

解决方法1️⃣

这个跳出递归的方法有待改善。。。

#include <stdio.h>
#include <string.h>
int k,m,a[20],n,flag=0;
void num(int e,int f)
{
	int i=0,j=0;
	flag=fla(flag);
	if(flag)
	{
		return 0;
	}
	else
	{
		for(i=0;i<k;)
		{
			if(a[(e+i)%n]==0) e++;
			else i++;
		}
		for(j=0;j<m;)
		{
			if(a[(f-j+n)%n]==0) f--;
			else j++;
		}
		if(a[(e+i-1)%n]==a[(f-j+n+1)%n]) printf("%d ",a[(e+i-1)%n]);
		else printf("%d %d ",a[(e+i-1)%n],a[(f-j+n+1)%n]);
		a[(e+i-1)%n]=0;
		a[(f-j+n+1)%n]=0;
		num((e+i-1)%n,(f-j+n+1)%n);
	}
	
 } 
 
 int fla(int flag)
 {
 	int i;
 	for(i=0;i<n;i++)
	{
		if(a[i]!=0)
		{
			return flag=0;
		}
	}
	return flag=1;
 }
 
 void main()
 {
 	int i;
 	scanf("%d%d%d",&n,&k,&m);
	for(i=1;i<=n;i++)
 	{
 		a[i-1]=i;
	 }
	num(0,n-1);
 }

解决方法2️⃣

目前的最优解(循环调用函数)

#include<stdio.h>
#define maxn 25
int n, k, m, a[maxn];
//逆时针走t步,步长是d(-1表示顺时针走),返回新位置
int go(int p, int d, int t) {
    while(t--) {
    do { p = (p+d+n-1) % n + 1; } while(a[p] == 0); //走到下一个非0数字
    }
    return p;
}

void main() {
	int i;
	scanf("%d%d%d", &n, &k, &m);
    for(i = 1; i <= n; i++) a[i] = i;
    int left = n; //还剩下的人数
    int p1 = n, p2 = 1;
    while(left) {
        p1 = go(p1, 1, k);
        p2 = go(p2, -1, m);
        printf("%3d", p1); left--;
        if(p2 != p1) { printf("%3d", p2); left--; }
        a[p1] = a[p2] = 0;
        if(left) printf(",");
    }
    printf("\n");

}

解决方法3️⃣

链表,容易理解,拓展性强

#define NULL 0
#define LEN sizeof(struct stu)
int n;
struct stu
{
	int num;
	struct stu *breaky;
	struct stu *back;
	struct stu *next;
};
struct stu *p,*op;
struct stu *create(int n)
{
	struct stu *head,*new,*tail;
	int count = 1;
	while(count<=n)
	{
		new = (struct stu * ) malloc(LEN);
		new->num=count;
		if(count==1)
		{
			head = new; tail=new;
		}
		else
		{
			new->back=tail;
			tail->next=new;   //自左向右结合
			tail=new;
		}
		count++;
	}
	tail->breaky=NULL;
	tail->next=head;
	head->back=tail;
	return(head);
}

void newlo(int b,int k)
{
	struct stu *m,*l;
	k--; b--;
	while(--k)
	{
		p=p->next;
	}
	while(--b)
	{
		op=op->back;
	}
	m=p; l=op;
	p=p->next;
	op=op->back;
	printf("%d ",p->num); n--;
	if(p->num!=op->num)
	{
		printf("%d ",op->num); n--;
	}
	if(p->next==op)
	{
		m->next=l; l->back=m;
	}
	else if(op->next==p)
	{
		op->back->next=p->next; p->next->back=op->back;
	}
	else
	{
		m->next=p->next; p->next->back = m;
		l->back=op->back; op->back->next = l; 
	}
}

void main()
 {
 	int k,b;
 	struct stu *temp;
 	scanf("%d%d%d",&n,&k,&b);
	p = create(n);
	temp = p;
	while(p->breaky!=NULL)
	{
		p=p->next;
	}
	op=p;
	p=temp;
	while(n)
	{
		newlo(b,k);
		if(p->next==op)
		{
			p=p->next;
			op=op->back;
		}
		p=p->next;
		op=op->back;
	}
 }

拓展

只需要逆时针数数(链表很简单)

#define NULL 0
#define LEN sizeof(struct stu)
struct stu
{
	int num;
	struct stu *breaky;
	struct stu *back;
	struct stu *next;
};
struct stu *p;
int flag=0;
struct stu *create(int n)   //只考虑逆时针的话可以把back去掉并且不需要breaky
{
	struct stu *head,*new,*tail;
	int count = 1;
	while(count<=n)
	{
		new = (struct stu * ) malloc(LEN);
		new->num=count;
		if(count==1)
		{
			head = new; tail=new;
		}
		else
		{
			new->back=tail;
			tail->next=new;   //自左向右结合
			tail=new;
		}
		count++;
	}
	tail->breaky=NULL;
	tail->next=head;
	head->back=tail;
	return(head);
}
void *newlo(int k)
{
	struct stu *m;
	k--;
	while(--k)
	{
		p=p->next;
	}
	m=p;
	p=p->next;
	printf("%d ",p->num);
	m->next=p->next;
	if(p==m)
	{
		flag=1;
	}
}
void main()
 {
 	int n,k,b;
 	//struct stu *temp;
 	scanf("%d%d%d",&n,&k,&b);
	p = create(n);
	//temp = p;
	/*while(p->breaky!=NULL)
	{
		p=p->next;
	}
	op=p;*/
	//p=temp;
	while(!flag)
	{
		newlo(k);
		/*if(p->next==op)
		{
			p=p->next;
			op=op->back;
		}*/
		p=p->next;
		//op=op->back;
	}
 }


只需要顺时针数数(链表很简单)

#define NULL 0
#define LEN sizeof(struct stu)
struct stu
{
	int num;
	struct stu *breaky;
	struct stu *back;
	struct stu *next;
};
struct stu *p,*op;
int flag=0;
struct stu *create(int n)
{
	struct stu *head,*new,*tail;
	int count = 1;
	while(count<=n)
	{
		new = (struct stu * ) malloc(LEN);
		new->num=count;
		if(count==1)
		{
			head = new; tail=new;
		}
		else
		{
			new->back=tail;
			tail->next=new;   //自左向右结合
			tail=new;
		}
		count++;
	}
	tail->breaky=NULL;
	tail->next=head;
	head->back=tail;
	return(head);
}
void newlo(int b)
{
	struct stu *l;
	b--;
	while(--b)
	{
		op=op->back;
	}
	l=op;
	op=op->back;
	printf("%d ",op->num);
	l->back=op->back;
	if(op==l)
	{
		flag=1;
	}
}
void main()
 {
 	int n,k,b;
 	struct stu *temp;
 	scanf("%d%d%d",&n,&k,&b);
	p = create(n);
	temp = p;
	while(p->breaky!=NULL)
	{
		p=p->next;
	}
	op=p;
	p=temp;
	while(!flag)
	{
		newlo(b);
		/*if(p->next==op)
		{
			p=p->next;
			op=op->back;
		}*/
		//p=p->next;
		op=op->back;
	}
 }
赞赏