XTU-OJ 1432-Cycle

文章介绍了如何使用数组链表的方法解决一个计数问题,给定n个数字形成一个圆圈,按照特定规则删除数字,直到只剩下一个。文章提供了两种方法实现,一种是数组链表,另一种是更新数组法。

题目描述

数字 1∼n顺时钟排成一个圈,从1开始顺时钟计数,数到的数退出这个圈,然后从下一个数字开始数,直到剩下最后一个数字。 计数的序列为{a1,a2,…,an−1}, 其中 ai=(ai−1+ai−2)%n+1,i>2 且 1≤a1,a2≤n。

比如n=5,计数序列的前两项为{1,2}时,整个计数序列为{1,2,4,2},那么第一次去掉数字1,得到数字圈为{2,3,4,5}; 再从2开始,数两个数,到数字3,去掉得到数字圈为{4,5,2};依次,再数4个数,到数字4,去掉得到数字圈为{5,2};最后数2个数,去掉2,剩下5。

请你写个程序,在已知n,a1,a2的情况下,求最后剩下的数?

输入

第一行是一个整数T(1≤T≤1000),表示样例的个数。

以后每行一个样例,为三个整数n(2≤n≤1000),a1,a2(1≤a1,a2≤n)。

输出

每行输出一个样例的结果。

样例输入

2
3 2 3
5 2 3

样例输出

1
4

解题思路:本题是把n个数排成一个圆,每次循环去掉一个数。依次循环找到最后剩下的数。第一反应是用链表的方法来解,但大家可能还不太熟悉 指针和结构体,所以这里用了 另一个链表方法:数组链表。(但是还是推荐大家去学一下指针和结构体,就算下面的数组双向链表,也用结构体数组写比较好。)

typedef struct List
{
    int num;      // 数字
    int head;     // 前置节点  题目中的 books[][0];
    int tail;     // 后置节点 == 题目中的 books[][1];
}list[1010];

数组链表: 用二维数组模拟双向链表,books[][0],保存当前数前一个数是多少,books[][1]保存当前数 后一个数是多少 。 比如下图,books[1][0] = 4, books[1][1] = 2 ,表示数字1 前一个数 是4,后一个数是2; books[3][0] = 2, books[3][1] = 4,表示数字3 前一个数 是2,后一个数是4。

现在假如 删除了数字2,那么1后面就接的是3了,3前面一个数就是1了。所以要更新二维数组,books[1][1] = 3, books[3][0] = 1。 这样我们就实现了题目中 去掉对应数字 这一步。

题外话:这是不是很简单就实现了元素删减,但上面为什么还说推荐用结构体数组呢?因为这题,恰好 初始的数字序列和数组下标对的上,是用 1、2、3、4、·····、n-1、n 这么递增上去的,和数组第一维的下标变化一致。但如果现在改变一下题目:圆圈是由各个奇数 1、3、5、······、n-2、n组成的,那么用这种二维数组还方便吗?如果用结构体,直接就可以用 list[i].num 存下每个数值。

AC代码:

方法一:数组链表

#include <stdio.h>

int T,n,end;
int ai[1010],books[1010][3] = {0};
int main()
{
    scanf("%d",&T);
    while ( T --)
    {
        scanf("%d %d %d",&n,&ai[1],&ai[2]);
        books[1][0] = n, books[n][0] = n-1;          // 初始化链表
        books[1][1] = 2, books[n][1] = 1;
        for (int i = 2; i < n; i ++){
            books[i][0] = i-1; books[i][1] = i+1;
        }
        for (int i = 3; i < n; i ++)                 // 把每一轮要走的步数算出来
            ai[i] = (ai[i-2]+ai[i-1])%n + 1;
        end = 1;                                     // 初始在 数字1 位置上
        for (int i = 1; i < n; i ++)                 // 开始删除“圆圈”里的数
        {
            for (int j = 1; j < ai[i]; j ++)         // 走ai[i] 步
                end = books[end][1];                
            books[books[end][0]][1] = books[end][1]; // 更新链表
            books[books[end][1]][0] = books[end][0];
            end = books[end][1];
        }
        printf("%d\n",end);
    }
    return 0;
}

方法二:更新数组法

#include <stdio.h>

int T,n,end,len;
int ai[1010],books[1010] = {0};
int main()
{
    scanf("%d",&T);
    while ( T --)
    {
        scanf("%d %d %d",&n,&ai[1],&ai[2]);
        for (int i = 1; i <= n; i ++)        // 初始化
            books[i] = i;
        
        for (int i = 3; i < n; i ++)
            ai[i] = (ai[i-2]+ai[i-1])%n + 1;
        end = 1, len = n;                       // len表示当前数组长度
        for (int i = 1; i < n; i ++, len --)    // 循环n-1次,相当于走n-1步
        {
            end = (end+ai[i]-1)%len;            // 直接定位到该轮 该删去数 的位置
            if (end == 0)  end = len;
            for (int j = end; j < len; j ++)    // 把删去数后面的所有数往前移(更新数组)
                books[j] = books[j+1];
            if (end == len) end = 1;
        }
        printf("%d\n",books[1]);                // 最后只剩下books[1],就是目标数了
    }
    return 0;
}

06-16
### XTUOJ 使用指南 XTUOJ 是一个在线评测系统,主要用于算法竞赛训练、编程能力提升以及学习算法知识。以下是关于 XTUOJ 的使用方法和技术信息的详细介绍: #### 1. 注册与登录 用户需要访问 XTUOJ 官方网站进行注册和登录。注册时需提供有效的邮箱地址,并设置用户名和密码。登录后可以参与题目练习、比赛等活动[^1]。 #### 2. 题目分类与查询 XTUOJ 提供了多种题型分类,例如数学专题、素数问题、模拟题等。用户可以通过导航栏选择不同类型的题目进行练习。此外,还可以通过搜索功能输入关键词快速定位目标题目[^2]。 #### 3. 提交代码与结果反馈 在完成题目解答后,用户需将代码提交至系统。支持的语言包括 C、C++、Python 等。提交后,系统会自动运行测试用例并对代码进行评判,返回结果如 "Accepted"(正确)、"Wrong Answer"(答案错误)或 "Time Limit Exceeded"(超时)等状态信息[^3]。 #### 4. 比赛模式与排行榜 XTUOJ 支持举办各类编程竞赛,在比赛模式下,参与者需在规定时间内解决若干道题目。系统会根据解题数量及耗时生成实时排名榜,激励选手提高效率与准确性[^4]。 #### 5. 常见问题与调试技巧 - **TLE(Time Limit Exceeded)**:如果遇到程序运行时间过长的问题,建议优化算法复杂度或减少不必要的循环操作。 - **WA(Wrong Answer)**:仔细检查边界条件处理是否得当,确保所有测试数据均能正确处理。 - **MLE(Memory Limit Exceeded)**:注意控制内存使用量,避免创建过大数组或递归深度过深。 ```python # 示例代码:判断素数 def is_prime(n): if n <= 1: return False for i in range(2, int(n**0.5) + 1): if n % i == 0: return False return True ``` #### 6. 技术文档与资源推荐 对于希望深入了解 XTUOJ 平台技术实现的用户,可以参考以下资源: - 官方帮助文档:详细介绍了平台架构设计、API 接口调用等内容。 - 社区论坛:与其他开发者交流心得体验,获取更多实用技巧[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值