例题 4-3 救济金发放(The Dole Queue) UVa 133

题目:

为了缩短领救济品的队伍,NNGLRP决定了以下策略:每天所有来申请救济品的人会被放在一个大圆圈,面朝里面。选定一个人为编号 1 号,其他的就从那个人开始逆时针开始编号直到 N。一个官员一开始逆时针数,数 k 个申请者,然后另一个官员第 N 个始顺时针方向数 m 个申请者,这两个人就出圆圈。如果两个官员数的是同一个人,那个人则出圈,如果选了两个不同的人,则先输出第一个第一个官员数出的那个人,然后2个官员再在剩下的人里面继续选直到没人剩下来,注意两个被选 中的人是同时走掉的,所以就有可能两个官员选中一个人。

#include<stdio.h>
#include<string.h>
#define maxn 1000
int a[maxn];
int n, k, m;
int go(int p, int d, int t) //巧妙 
	{
		while(t--){
			do{
				p = (p+d+n)%n;
			}while(a[p] == 0);
		}
		return p;
	}
int main()
	{
		int people;
		while(scanf("%d%d%d",&n,&k,&m) == 3 && !(n == 0 && k == 0 && m == 0)){
			for(int i = 0; i < n; i++ ){
				a[i] = i+1;
			}
			int left = n;//剩余 人数 
			int p1 = n-1, p2 = 0; // p指向起始处的前一个位置 
			while(left){
				p1 = go(p1, 1, k);
				p2 = go(p2, -1, m);
				printf("%3d", p1+1);//注意 出队人的序号比索引大 1 (数组下标从零开始的)
				left--;
				if(p2 != p1){
					printf("%3d",p2+1);
					left--;
				}
				a[p1] = a[p2] = 0;
				if(left)
					printf(",");	
			}
			printf("\n");
		}
		
		return 0;
	}

go函数每走一步都得到下一个位置
解析:至于下一个位置为什么是p = (p+n+d)%n.其实很简单。因为我们是一步步走的,所以只有两种边界情况。假设当前位置是p(0=<p<n),
第一种边界:p + 1 > n - 1,即 p + 1此时应该是到达0位置,但此时p + 1 = n,如果我们取余数,则 (p+1)%T = 0,T = n(T表示这个圆圈的周期大小)。
刚好能符合,又因为T = n,所以(P+T+1)%T还是不变的。
第二种边界: p - 1 < 0, 即 p - 1此时的值是-1,对于这种情况可以反过来看,它是向后退后1个单位,可以看成向前走T - 1个单位即p -1 等效于 p + T - 1
,我们要等到此时的位置,再去余,(P+T-1)%T。
对于情况一、二。可以归纳为(P+T+d)%T,当为顺时针是d取1,否则-1.


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值