题目
试题编号: 201712-2
试题名称: 游戏
时间限制: 1.0s
内存限制: 256.0MB
使用语言:C++
得分:90
问题描述
有n个小朋友围成一圈玩游戏,小朋友从1至n编号,2号小朋友坐在1号小朋友的顺时针方向,3号小朋友坐在2号小朋友的顺时针方向,……,1号小朋友坐在n号小朋友的顺时针方向。
游戏开始,从1号小朋友开始顺时针报数,接下来每个小朋友的报数是上一个小朋友报的数加1。若一个小朋友报的数为k的倍数或其末位数(即数的个位)为k,则该小朋友被淘汰出局,不再参加以后的报数。当游戏中只剩下一个小朋友时,该小朋友获胜。
例如,当n=5, k=2时:
1号小朋友报数1;
2号小朋友报数2淘汰;
3号小朋友报数3;
4号小朋友报数4淘汰;
5号小朋友报数5;
1号小朋友报数6淘汰;
3号小朋友报数7;
5号小朋友报数8淘汰;
3号小朋友获胜。
给定n和k,请问最后获胜的小朋友编号为多少?
输入格式
输入一行,包括两个整数n和k,意义如题目所述。
输出格式
输出一行,包含一个整数,表示获胜的小朋友编号。
样例输入
5 2
样例输出
3
样例输入
7 3
样例输出
4
数据规模和约定
对于所有评测用例,1 ≤ n ≤ 1000,1 ≤ k ≤ 9。
解题思路
对于这个题我的解题思路非常简单,采用了循环链表,每一个结点代表一个小朋友,每次遇到满足题目条件的小朋友就删除一个结点,最后当循环链表只剩下一个结点时,就得到了结果;
对于循环链表的初始化部分有一个要注意的问题就是临时结点一定要用new创建,分配在堆空间,而不要采用child x这样分配在栈空间的方式,因为那样会导致只会创建一次x,地址都是相同的,达不到创建链表的目的;
另外题只得了90分,原因是运行超时。采用循环链表这种方式逻辑确实非常简单,但是时间复杂度和空间复杂度确实很大;我之后计算出满分的解题方式会继续更新。
代码
#include <iostream>
using namespace std;
//循环链表结点
struct child
{
int num;
child *next;
};
int main()
{
// sum记录剩下的人数
int n, k, sum;
child A;
child *temp;
child *p;
temp = &A;
scanf("%d%d", &n, &k);
sum = n;
for (int i = 1; i < n; i++)
{
temp->num = i;
child *x = new child();
// child x;不可以这样,每一次循环都是同一个x,地址都是一样的,要使用new将x放在堆中
temp->next = x;
temp = x;
}
temp->num = n;
//一方面使单链表变成循环链表,另一方面方便删除下一个节点
temp->next = &A;
//从第一个小朋友开始
p = &A;
for (int i = 1; sum > 1; i++)
{
//报到k的倍数或其末位数(即数的个位)为k的数
while (i % k == 0 || i % 10 == k)
{
temp->next = temp->next->next;
i++;
sum--;
}
temp = temp->next;
}
printf("%d", temp->num);
system("pause");
return 0;
}