对N个人按1到N进行编号,然后按顺序逆时针围成一圈。给定一个数m,从1号开始按逆时针方向数,每数到m,对应的人就从圈中出来,然后继续从下一个人开始数,直到圈中只剩下一个人,试输出出圈人的编号顺序。
程序运行效果图:
部分程序框图:
解题思路
序号 1 234 5 6 712 3 4 567
索引 0 123 4 5 678 9 10 111213
为了避开逆向读取时索引值超出范围的问题,于是产生2个一样的具有N个元素的数组,以1~N的形式对数组元素赋值并将其连接成一个数组,例如12345671234567。每次逆向操作删除一个元素(对应一个人出列)时都以数组的后一部分1234567作为起点,这样操作能保证被操作数不会超出数组索引范围。
用输入的M值对N求余,即M%N,余数表示元素在数组中的实际逆向偏移量。例如,当M为12,M%N即12%7=5,也就是逆向数到第12个人和逆向数到第5个人等效。根据本题的要求,从序号为1的元数开始数到12,那么序号为4的元素就是第一次要出列的人。设序号为1的元数的索引为index,则序号为4的元素的索引为index-(M%N-1)。因为第1次是从序号为1的元素数开始的,所以index是固定的,即index=N。
从数组后半部分(指数组后一个1234567序列的组合,下同)序号为1的元数起,第一次删除一个由M%N指定的元素(即第一个人出列),则这个元素必定落在数组的前半部分。例如当M等于12时序号为4的元素就是第一次要出列的人。那么下一次出列就从序号为3的元素开始:
序号 1 235 6 7 123 5 6 7
索引 0 123 4 5 678 9 10 11
但是当从序号为3的元素开始删除一个元素时,如何保证index-(M%N1-1)不超出数组的范围?答案是从数组的后半部分序号为3的元素开始,而不是前半部分!设法求出后半部分序号为3的元素的索引值,就能求index-(M%N1-1)的值(N1为删除前后部分相同一个元素后数组的新大小),而这个值就是下一个要删除的元素的索引,往后依此类推,当整个数组只剩下2个元素时则出列完毕。
示例程序源代码下载地址:http://download.csdn.net/detail/marlboro_1999/7148007