P1540 [NOIP 2010 提高组] 机器翻译

P1540 [NOIP 2010 提高组] 机器翻译 解题思路与代码注释

解题思路

这道题目考察的是队列和缓存替换算法的应用,具体实现的是FIFO(先进先出)的缓存替换策略。

核心思路

  1. 使用一个队列来维护当前内存中的单词,队列长度不超过内存容量M

  2. 使用一个标记数组vis来记录单词是否在内存中

  3. 对于每个新单词:

    • 如果已经在内存中(vis[x]为真),则不需要查词典

    • 如果不在内存中:

      • 查词典次数+1

      • 将单词加入队列

      • 如果队列已满(M个单词),则移除队首单词(最早进入的)

      • 更新标记数组

代码注释(STL队列实现)

#include<bits/stdc++.h>
using namespace std;
int m,n; // m:内存容量 n:文章长度
int vis[1001]; // 标记数组,记录单词是否在内存中(0表示不在)
queue<int> q; // 使用队列维护内存中的单词(FIFO)
int ans; // 记录查词典的次数

int main()
{
    cin >> m >> n; // 输入内存容量和文章长度
    for(int i = 1; i <= n; i++) // 处理每个单词
    {
        int x; cin >> x; // 读取当前单词
        if(!vis[x]) // 如果单词不在内存中
        {
            ans++; // 需要查词典
            vis[x]++; // 标记为在内存中
            q.push(x); // 加入队列
            if(q.size() > m) // 如果内存已满
            {
                int top = q.front(); q.pop(); // 移除最早进入的单词(队首)
                vis[top]--; // 更新标记
            }
        }
    }
    cout << ans; // 输出总查词典次数
    return 0;
}

数组模拟队列实现

#include<bits/stdc++.h>
using namespace std;

int m,n;
int vis[1001]; // 标记数组
int q[1001]; // 数组模拟队列
int head = 0, tail = 0; // 队首和队尾指针
int ans = 0; // 查词典次数

int main()
{
    cin >> m >> n;
    for(int i = 1; i <= n; i++)
    {
        int x; cin >> x;
        if(!vis[x]) // 单词不在内存中
        {
            ans++; // 查词典次数增加
            vis[x] = 1; // 标记为存在
            q[tail++] = x; // 入队
            if(tail - head > m) // 如果超过内存容量
            {
                vis[q[head]] = 0; // 移除最早单词的标记
                head++; // 队首指针后移
            }
        }
    }
    cout << ans;
    return 0;
}

两种实现对比

  1. STL队列实现:

    • 优点:代码简洁,直接使用标准库提供的队列操作

    • 缺点:隐藏了底层实现细节

  2. 数组模拟队列:

    • 优点:更直观展示队列工作原理,便于理解

    • 缺点:需要手动维护头尾指针

算法分析

  • 时间复杂度:O(N),每个单词只处理一次

  • 空间复杂度:O(M),队列最多存储M个单词

该算法完美模拟了FIFO缓存替换策略,是理解操作系统内存管理和缓存算法的经典例题。

posted @ 2025-05-27 15:58  CRt0729  阅读(40)  评论(0)    收藏  举报