1. 问题描述
n 个孩子在玩一个游戏。 孩子们站成一圈,按照顺时针顺序分别被标号为 1 到 n。开始游戏时,第一个孩子成为领导。 游戏进行 k 轮。 在第 i 轮中,领导会从他顺时针方向下一个孩子开始数 ai 个孩子。最后数到的那个孩子出局,再下一个孩子成为新的领导。 举个例子, 现在圈内还剩 [8, 10, 13, 14, 16]5个孩子,领导编号为 13 , ai = 12。那么出局的孩子为 16 。第 8 个孩子成为下一个领导。 你需要写一个代码模拟这个过程,求出每轮比赛出局的孩子。 第一行包含两个整数 n 和 k (2 ≤ n ≤ 100, 1 ≤ k ≤ n - 1). 第二行包含 k 个整数 a1, a2, ..., ak (1 ≤ ai ≤ 1e9). 输出 k 个整数,第 i 个整数表示第 i轮出局的孩子。
输入输出样例
输入 #1
7 5 10 4 11 4 1
输出 #1
4 2 5 6 1
输入 #2
3 2 2 5
输出 #2
3 2
2.思路分析
由题意会有孩子出局,所以存储孩子的标号应该是动态的,且本游戏数到末尾又会回到第一个数继续数,因此我们可以采用单向循环链表。链表的结构体包括两个内容:一是int型来存储标号,二是指向本结构体的指针。当数到对应结点时,则删除此结点,继续数下一个,以此类推。
3.算法描述
(1)键盘输入n和k,表示孩子的个数以及总轮数 (2)创建单向循环链表并标号1到n (3)创建数组ai,来存储每轮要数的孩子的个数,由于个数范围较大(1-1e9),因此可以定义为long long类型的数组 (4)循环遍历每一个ai,利用取模即ai%n(结果为要数的孩子数)来减少循环的次数,就不用数那么多轮了 (5)当找到要删掉(即要踢出局的人)时,把结点删掉,并将左右结点连接,继续数下一轮,直到k轮全部数完
注意:在删除结点时,要删除的结点要分首结点、尾结点和其他结点三部分分别进行讨论,具体情况具体处理
4.代码实现
#include<iostream>
using namespace std;
typedef struct node{
int a;
struct node *next;
}Node;
int main()
{
Node *head,*rear,*last,*q;
int n,k,i;
cin>>n>>k;
Node *p;
head=NULL; //建立动态链表
for(i=1;i<=n;i++){
p=new Node;
p->a=i;
if(head){
rear->next=p;
rear=p;
}else{ //没有空结点的链表
head=p;
rear=head;
}
}
rear->next=head; //创建单向循环链表
long long ai[105]; //由于ai范围在1-1e9较大
for(i=0;i<k;i++){
cin>>ai[i];
}
last=head; //首结点为第一轮的领导
q=rear;
/*注意此处q不应该赋值为NULL,应该赋值为尾结点的地址,
否则当第一轮要删除的结点为头结点时,无法对尾结点的next进行赋值为head,
构成循环链表,且当赋值为NULL时,q->next程序会异常 */
for(i=0;i<k;i++){
ai[i]%=n; //减少下面循环的次数,结果为要继续数的人数
for(;ai[i]!=0;ai[i]--){
q=last; //last最终指向要删除的结点,而q是用来连接左右结点的
last=last->next;
}
cout<<last->a<<' ';
n--;
if(i==k-1)return 0; //当i==k-1即说明此时是最后一轮了,无需再进行删除结点的操作
//删除结点分三种情况讨论:头结点、尾结点、其他结点
if(last==head){
head=last->next;
q->next=head; //让尾部指向头结点
}else if(last->next==head){
q->next=head; //让尾部指向头节点
}else{
q->next=last->next; //让被删除结点的左右结点连接
}
delete(last); //清除要删除的结点
last=q->next; //指向被删除结点的下一个(即领导)
}
return 0;
}
5. 程序执行结果
6.分析与总结
该程序的平均时间复杂度为O(k*n/2),其中k为轮数,n为小孩的数量 注意: (1)对链表的创立与删除要依据具体情况具体分析 (2)对于数据范围较大的可以采用long long甚至unsigned long long
ps:此题也可以用数组的方式,即创建一个数组,下标表示小孩的标号,从1开始到n,舍弃0;先初始化数组为0,此后每次出局便赋值为1,在数人的时候跳过那些1即可,较为容易实现,不多介绍,下面附上代码:
#include<iostream>
using namespace std;
int main()
{
long long ai[100];
int test[105]={0};
int n,k,i,j,x;
cin>>n>>k;
for(i=0;i<k;i++){
cin>>ai[i];
}
int count=0;
int t=n;
for(i=0,j=1;i<k;i++){
if(count==-1){
if(j==n)j=0;
for(x=j+1;test[x]==1;x++){
if(x>=n)x=0;
}
count=0;
j=x;
}
ai[i]%=t;
while(count<ai[i]){
if(j+1<=n&&test[j+1]!=1)count++;
if(j<n)j++;
else j=0;
}
cout<<j<<' ';
test[j]=1;
count=-1;
t--;
}
return 0;
}