题目链接:
考虑使用循环链表来维护该环形数据结构。但下列代码只能通过70/100
#include <bits/stdc++.h>
using namespace std;
int ne[50];
int main()
{
int k, n, m;
bool flag = true;
cin >> k;
n = 2 * k, m = k + 1;
for (int i = 1; i < n; i++) ne[i] = i + 1;
ne[n] = 1;
int p = n, t = k;
for (; ; m++) {
flag = true;
p = n, t = k;
for (int i = 1; i < n; i++) ne[i] = i + 1;
ne[n] = 1;
while (t--) {
for (int i = 1; i < m; i++) p = ne[p];
if (ne[p] >= 1 && ne[p] <= k) {
flag = false;
break;
}
else ne[p] = ne[ne[p]];
}
if (!flag) continue;
else {
cout << m;
return 0;
}
}
return 0;
}
经过思考,当\(\rm m\)的值较大(远远超过剩余总人数)的时候,寻找\(\rm p\)的过程有大量重复。事实上,只需走\(\rm m\)%\(\rm sum\)步(其中\(\rm sum\)为剩余总人数)即可,重复了好几圈。
值得注意的是,当\(\rm m\)%\(\rm sum\)为\(0\)的时候,for循环中的for (int i = 1; i < m%sum; i++)
这一步会不执行,且发现规律是删除自己的这个元素。因此需要用到节点的前驱节点。考虑改用双向循环链表维护。
易错点:1、在每次删除完节点之后,要修改某些节点的ne[]和pre[]的值(pre不能忘)
2、m++之后进入到一轮新的循环,链表的结构需要重新定义,指针p的初始指向,sum等变量的值要和初始时一致。
以下是AC代码。
#include <bits/stdc++.h>
using namespace std;
int ne[150], pre[150];
int main()
{
int k, n, m, sum;
bool flag = true;
cin >> k;
n = 2 * k, m = k + 1, sum = 2 * k;
for (int i = 1; i < n; i++) ne[i] = i + 1;
ne[n] = 1;
int p = n, t = k;
for (; ; m++) {
flag = true;
p = n, t = k, sum = n;
for (int i = 1; i < n; i++) ne[i] = i + 1;
ne[n] = 1;
pre[1] = n;
for (int i = 2; i <= n; i++) pre[i] = i - 1;
while (t--) {
int y = m % sum;
if (y == 0) p = pre[p];
else for (int i = 1; i < y; i++) p = ne[p];
if (ne[p] >= 1 && ne[p] <= k) {
flag = false;
break;
}
else {
ne[p] = ne[ne[p]];
pre[ne[p]] = p;
sum--;
}
}
if (!flag) continue;
else {
cout << m;
return 0;
}
}
return 0;
}
标签:int,sum,ne,约瑟夫,++,flag,P1145,rm
From: https://www.cnblogs.com/pangyou3s/p/17964480