救济金发放问题

问题:救济金发放(The Dole Queue, UVa 133


n(n<20)个人站成一圈,逆时针编号为1~n。有两个官员,A从1开始逆时针数,B从n开 始顺时针数。在每一轮中,官员A数k个就停下来,官员B数m个就停下来(注意有可能两个 官员停在同一个人上)。接下来被官员选中的人(1个或者2个)离开队伍。
输入n,k,m输出每轮里被选中的人的编号(如果有两个人,先输出被A选中的)。例 如,n=10,k=4,m=3,输出为7 3, 2 6, 8 10, 9 5, 1, 4。注意:输出的每个数应当恰好占3列。

分析:利用数组来表示每一个位置,用零标记被抽走的人防止再次被抽

C语言代码:

#include<stdio.h>
#define  maxn 25
int n,p1,p2,k,m,a[maxn];//p1,p2记录两官员当前位置
int p1_guess(int p1,int k)//A官员行走函数 
{
	while(k--)
	{
		do
		{
		p1=(p1-1+n-1)%n+1;//计算A的移动
		}while(a[p1]==0);//走到下一个非零数字
		
	}
	return p1;
};
int p2_guess(int p2,int m)//B官员行走函数
{
	while(m--)
	{
		do
		{
		p2=(p2+1+n-1)%n+1;//计算B的移动
		}while(a[p2]==0);//走到下一个非零数字
		
	}
	return p2;

};
int main()
{
	while(scanf("%d%d%d",&n,&k,&m)==3&&n)
	{
		int left=n;//记录剩下的人
		for(int i=1;i<=n;i++)
			a[i]=i;
		p1=1;
		p2=n;
		while(left)
		{
			p1=p1_guess(p1,k);
			p2=p2_guess(p2,m);
			if(p1==p2)
				printf("%3d",p1);
			else
			{
				printf("%3d",p1);
				printf("%3d",p2);
			}
			a[p1]=a[p2]=0;//用零来补上被抽中的人防止再被抽
			left--;
			if(left)
				printf(",");
		}
		printf("\n");

	}
	return 0;

}

p1_guess()与p2_guess其实可以合并,用+1表示顺时针,-1表示逆时针,合并后代码如下:

#include<stdio.h>
#define  maxn 25
int n,p1,p2,k,m,a[maxn];//p1,p2记录两官员当前位置

int guess(int p,int len,int t)//B官员行走函数
{
	while(t--)
	{
		do
		{
		p=(p+len+n-1)%n+1;//计算B的移动
		}while(a[p]==0);//走到下一个非零数字
		
	}
	return p;

};
int main()
{
	while(scanf("%d%d%d",&n,&k,&m)==3&&n)
	{
		int left=n;//记录剩下的人
		for(int i=1;i<=n;i++)
			a[i]=i;
		p1=1;
		p2=n;
		while(left)
		{
			p1=guess(p1,-1,k);
			p2=guess(p2,+1,m);
			if(p1==p2)
				printf("%3d",p1);
			else
			{
				printf("%3d",p1);
				printf("%3d",p2);
			}
			a[p1]=a[p2]=0;//用零来补上被抽中的人防止再被抽
			left--;
			if(left)
				printf(",");
		}
		printf("\n");

	}
	return 0;

}

思考:为何是围成一圈,可一维数组可以实现?

诀窍其实在此公式:p=(p+len+n-1)%n+1;
巧妙的解决了这个问题

发布了9 篇原创文章 · 获赞 3 · 访问量 543

猜你喜欢

转载自blog.csdn.net/Anterior_condyle/article/details/104183982
今日推荐