> 文档中心 > 【PTA】特殊约瑟夫问题 + 重排链表

【PTA】特殊约瑟夫问题 + 重排链表


 

目录

1.题目描述

2.输入输出

3.解题思路

4.样例解析

5.代码实现


1.题目描述 

编号为1…N的N个小朋友玩游戏,他们按编号顺时针围成一圈,从第一个人开始按逆时针次序报数,报到第M个人出列;

然后再从下个人开始按顺时针次序报数,报到第K个人出列;再从下一个人开始按逆时针次序报数,报到第M个人出列;再从下个人开始按顺时针次序报数,报到第K个人出列……

以此类推不断循环,直至最后一人出列。请编写程序按顺序输出出列人的编号。

输入为3个正整数,分别表示N、M、K,均不超过1000。

输出为一行整数,为出列人的编号。每个整数后一个空格。


2.输入输出

输入样例: 

6 3 5

输出样例:

5 3 1 2 4 6 


3.解题思路

这道题的话,我直接用一个数组来模拟,如果这个人出队的话,就将他标记为出队

这道题的难点是在如何实现题目的要求 :一个顺时针,一个逆时针

对于这个要求,我选择使用一个方向向量 step :

顺时针表示是 正方向 上的步数 ++ 

逆时针表示是 反方向 上的步数 ++

然后在每一次出队一个人后都更新一下 方向向量 出队要求(号数


4.样例解析

 以此类推


5.代码实现

记录数值 k 表示逆时针的号数,m 表示顺时针的号数

q[N]来表示每个号数的学生


首先初始化,将每个位置初始化为这个位置对应的号数


t 表示当前喊到的号数

rule 表示当前是顺时针或者是逆时针的号数规则

sig 表示当前所指到的学生的编号是多少

step 表示方向向量,是顺时针走还是逆时针走


当当前的号数还没喊道当前的规则时,就让下标往方向向量的位置运动

因为这个是一个环状结构,所以

当下标小于 1 的时候,传送到最后一个位置

当下标大于 n 的时候,传送到第一个位置

每次到达一个坐标的时候,都要判断一下当前这个号数的人是否出队


所以当前下标所对应的就是要出队的学生,将他的判断数组置为0

然后要记得到出队的下一个位置 

step * -1 起到了转换方向向量的作用

利用三目操作符将操作的规则转换

最后要记得将 喊出的号数 重置为 1


AC代码

#include using namespace std;const int N = 5010;int n, m, k; //逆时针 :k 顺时针 : mint q[N];int main(){    cin >> n >> m >> k;    for(int i = 1; i <= n; i ++ ) q[i] = i;    //  目前的编号 当前规则   下标      方向向量    int t = 1,    rule = m, sig = 1, step = -1;    for(int i = 1; i <= n; i ++ )    { while(t < rule) {     sig += step;     if(sig  n) sig = 1;     if(q[sig] != 0) t ++ ; } printf("%d ", sig); q[sig] = 0; sig += step; step *= -1; rule = (rule == m) ? k : m; t = 1;    }    return 0;}

1.题目描述

2.输入输出

3.解题思路

4.样例解析

5.代码实现


 1.题目描述 

给定一个单链表 L1​→L2​→⋯→Ln−1​→Ln​,

请编写程序将链表重新排列为 Ln​→L1​→Ln−1​→L2​→⋯。

例如:给定L为1→2→3→4→5→6,则输出应该为6→1→5→2→4→3。 

输入格式:

每个输入包含1个测试用例。每个测试用例第1行给出第1个结点地址和结点总个数,即正整数N (≤105)。结点的地址是5位非负整数,NULL地址用−1表示。

接下来有N行,每行格式为:

Address Data Next

其中Address是结点地址Data是该结点保存的数据,为不超过105的正整数;Next是下一结点的地址。题目保证给出的链表上至少有两个结点。

对每个测试用例,顺序输出重排后的结果链表,其上每个结点占一行,格式与输入相同。


 2.输入输出

 

输入样例: 

00100 6
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218

输出样例: 

68237 6  00100
00100 1  99999
99999 5  12309
12309 2  00000
00000 4  33218
33218 3  -1


 3.解题思路

这道题是一道链表的模拟题,我们要按照题目的要求来对所给的链表进行操作

注意到所有的地址不超过 1e5   所以我们直接使用数组的下标来作为地址方便运算

同时使用一个结构体来存储 数据 和 next指针

最后利用双指针算法 同时从两端开始来输出数据

按序输出地址即可 


 4.样例解析

初始条件

转变后


 5.代码实现

创建地址结点,包含data和next


 将起始地址和个数读入

然后依次读入地址,在对应的数组下标中读入相应的数据


定义一个 r 表示最右边的个数(总个数)

然后将当前的地址移动到第二个地址


当address != -1 的时候,一直递归处理,将链表中的地址按顺序存入a数组中


记得这一步 r -- 保证数据的准确性,不会多一个 ++  


用a数组依次存储原链表的各个内存地址,b来模拟新的链表各个内存地址

利用双指针算法,题目要求将数组存入b数组中


按题目规则打印即可 


 AC代码

#include #include #include using namespace std;const int N = 100010;struct Node {    int data, next;}q[N];int a[N], b[N];int main(){    int next, n, address;    cin >> next >> n;    for(int i = 1; i > address; scanf("%d %d", &q[address].data, &q[address].next);    } int r = 0; a[r ++ ] = next;    address = q[next].next; while(address != -1)    { a[r ++ ] = address; address = q[address].next;    }    r--;    int l = 0, pos = 0;    while(l <= r)    { b[pos ++ ] = a[r -- ]; if(l <= r) b[pos ++ ] = a[l ++ ];    } for(int i = 0; i < pos; i ++ )    { if(i != pos - 1) printf("%05d %d %05d\n", b[i], q[b[i]].data,b[i + 1]); else printf("%05d %d -1", b[i], q[b[i]].data);    }    return 0;}