紫书:The Dole Queue

看起来简单,实际上有很多东西可以仔细咀嚼!

Description
In a serious attempt to downsize (reduce) the dole queue, The New National Green Labour Rhinoceros Party has decided on the following strategy. Every day all dole applicants will be placed in a large circle, facing inwards. Someone is arbitrarily chosen as number 1, and the rest are numbered counter-clockwise up to N (who will be standing on 1’s left). Starting from 1 and moving counter-clockwise, one labour official counts off k applicants, while another official starts from N and moves clockwise, counting m applicants. The two who are chosen are then sent off for retraining; if both officials pick the same person she (he) is sent off to become a politician. Each official then starts counting again at the next available person and the process continues until no-one is left. Note that the two victims (sorry, trainees) leave the ring simultaneously, so it is possible for one official to count a person already selected by the other official.

Input
Write a program that will successively read in (in that order) the three numbers (N, k and m; k, m > 0, 0 < N < 20) and determine the order in which the applicants are sent off for retraining. Each set of three numbers will be on a separate line and the end of data will be signalled by three zeroes (0 0 0).

Output
For each triplet, output a single line of numbers specifying the order in which people are chosen. Each number should be in a field of 3 characters. For pairs of numbers list the person chosen by the counter-clockwise official first. Separate successive pairs (or singletons) by commas (but there should not be a trailing comma).

Samples
Input
10 4 3
0 0 0
Output
4 8, 9 5, 3 1, 2 6, 10, 7

前言
这个题真的太妙了
我愿称之为代码的艺术

题目大意
现在有n个人围成一个圈,然后有两名管理者分别从第一个人 逆时针 开始点人,从第n个人顺时针开始点人。逆时针的管理者每次将数到的第k个人移除圆圈队列,顺时针的管理者每次将数到的第m个人移除圆圈队列 。然后继续从当前空位置开始重复上述操作,一直这样操作下去,直到所有人都被移除圆圈队列,求出队列中人员离开的顺序。

样例解释
第一轮:逆时针 空→1→2→3→4
顺时针:空→10→9→8
(4,8被移除)

第二轮:逆时针:4→5→6→7→8(已经被移除了)→9
顺时针:8→7→6→5
(9,5被移除)

第三轮:逆时针:9→10→1→2→3
顺时针:5→4(已被移除)→3→2→1
(3,1被移除)

第四轮: 3→4(移除)→5(移除)→6→7→8(移除)→9(移除)→10→1(移除)→2;
顺时针 :1→10→9(移除)→8(移除)→7→6
(2,6被移除)

。。。。。。。。略。。。。。。。。。。

题目注意事项及小技巧

1.循环节的处理:正数的循环节可以直接用%进行操作,那么负数怎么办?(因为顺时针逆时针的区分,一定有一个要利用负数循环操作)
负数的循环取余可以通过 ( +n)%n的方法来进行操作!

2.多组输入的处理:
以0 0 0末尾结束,如果是以单0结尾,可以 &&n这样操作
,如果0 0 0结尾,可以 &&( n || k| | m) 这样操作

3.注意每次的标记是选完两个人之后再进行标记,让两人离开
而不是选一个标记一个,这里要搞清楚。

4.注意第一次选人的时候,是算上1 和 10 本身的,但是后续的选择并没有算上起点本身,这里要搞清楚!所以我们在循环查找的时候,我们的起点必须提前一个数字!(提前一位循环起点)!

5.循环结束条件:因为题目要求再所有人都离开之后结束,不如
就设一个数字t=n,每离开一个人t- -,最后 t=0时结束循环!

#include<bits/stdc++.h>
using namespace std;
int vis[100001];
int n;
int go(int start, int d, int step )//本题核心;用一个函数概括了顺时针和逆时针的情况! 
{
    for ( int i = 0; i < step; i ++ )
    {
        do//这个do while循环,保证每次一定是有效步数,走一次检测一次的态度! 
        //这个地方是本题的核心:一个走k步和m步,保证走的步数一定是有效步数
		//原思路:先走k步,如果不满足(判断),再往下一步一步走!直到找到一个满足的! 
		//而且这样也不能保证之前走的步一定是有效的,直接麻了! 
		//而且没有概括顺走和逆走不过就是一个+1-1的区别! 
        {
            start = ( start+d+n )%n;//满足环状结构!,负数的环形结构:太妙了,+n! 
        }while ( vis[start] );
    }
    return start;//0
}
int main()
{
    int k,m;
	while(cin>>n>>k>>m&&(n||k||m))//这里如果结尾是0 0 0结尾,而不是一个0结尾,可以这样写! 
	{
		memset(vis,0,sizeof(vis));
		int t=n;
		int ni=n-1;// 
		int shun=0;
		//这个题真的太叼了! 
		while(t)//这里可以不用flag盲目结束循环了! 
		{
			ni=go(ni,1,k); 
            shun=go(shun,-1,m);
            printf("%3d",ni+1); 
            t--;//每输出一个就--,知道所有的数字都被标记,这样就不用盲目的flag了! 
            if(shun!=ni)
            {
                printf("%3d",shun+1);//这里的+1太妙了,如果没有这个+1,10这个数字根本输出不来! 
                t--;
            }//输出问题:这个输出真的太诡异了:最后直接用 3d控制一下! 
            vis[shun]=vis[ni]=1;//写完之后再进行两次标记! 
            if (t)
                printf (",");//这个地方写的真妙啊! 
        }
        printf("\n");
	}
	return 0;
}

关于代码的分析总结(自我总结)

以下是我个人做题时遇到的一些问题总结

1.是否合法:我原本的思路是让当前位置先逆时针走k步,然后判断是否合法,如果不合法再进行while循环查找有效位置。
但是这样太麻烦了,而且前面k步也不能保证有效合法。
所以这里直接用一个do while循环保证走的每一步一定是合法!

2.函数思想:找到顺时针查找,和逆时针查找的规律,原来他们俩其实就是一个+1-1的差别,如果把两个查找分开写,真的是乱死了,所以这边写了一个函数,用形式参数d的正负来控制顺时针和逆时针。这样要简便的多!

3.循环思想:因为%的原因,在%循环查找时一定会出现一个0,但是我们很痛苦的就是,这是一个1-n的序列,并不会有0,所以我们只能用0表示n,
但是新的问题又出现了 输出的时候,我们的n会在输出的时候也输出0,为了解决这个问题,我研究出两种方法

1.正常循环,在结果=0的情况下特判输出n!

2.再将循环起点提前一个位置(之前为了满足查找时不算本身的条件时已经提前一位了):然后最后输出的时候对结果进行+1!

*上面的代码用的是第二种


题目不难,但是用函数来概括顺时针和逆时针的情况太美了
刚开始做题的时候没有想到,这就是一个大错误!
这样的函数思路再平时做题或者比赛可以很好的让我的代码
不至于乱掉,保持我的思路更加清晰!
2021/5/22.

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++编写程序,实现以下问题2、题目ID Codes(POJ1146) Time Limit: 1000MS Memory Limit: 10000K 描述: It is 2084 and the year of Big Brother has finally arrived, albeit a century late. In order to exercise greater control over its citizens and thereby to counter a chronic breakdown in law and order, the Government decides on a radical measure--all citizens are to have a tiny microcomputer surgically implanted in their left wrists. This computer will contains all sorts of personal information as well as a transmitter which will allow people's movements to be logged and monitored by a central computer. (A desirable side effect of this process is that it will shorten the dole queue for plastic surgeons.) An essential component of each computer will be a unique identification code, consisting of up to 50 characters drawn from the 26 lower case letters. The set of characters for any given code is chosen somewhat haphazardly. The complicated way in which the code is imprinted into the chip makes it much easier for the manufacturer to produce codes which are rearrangements of other codes than to produce new codes with a different selection of letters. Thus, once a set of letters has been chosen all possible codes derivable from it are used before changing the set. For example, suppose it is decided that a code will contain exactly 3 occurrences of a', 2 of b' and 1 of c', then three of the allowable 60 codes under these conditions are: abaabc abaacb ababac These three codes are listed from top to bottom in alphabetic order. Among all codes generated with this set of characters, these codes appear consecutively in this order. Write a program to assist in the issuing of these identification codes. Your program will accept a sequence of no more than 50 lower case letters (which may contain repeated characters) and print the successor code if one exists or the message No Successor' if the given code is the last in the sequence for that set of characters. 输入: Input will consist of a series of lines each containing a string representing a code. The entire file will be terminated by a line consisting of a single #. 输出: Output will consist of one line for each code read containing the successor code or the words 'No Successor'. 样例输入 abaacb cbbaa # 样例输出 ababac No Successor
最新发布
05-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值