缓存交换
【问题描述 】
在计算机中,CPU只能和高速缓存Cache直接交换数据。当所需的内存单元不在Cache中时,则需要从主存里把数据调入Cache。此时,如果Cache容量已满,则必须先从中删除一个。
例如,当前Cache容量为3,且已经有编号为10和20的主存单元。
此时,CPU访问编号为10的主存单元,Cache命中。
接着,CPU访问编号为21的主存单元,那么只需将该主存单元移入Cache中,造成一次缺失(Cache Miss)。
接着,CPU访问编号为31的主存单元,则必须从Cache中换出一块,才能将编号为31的主存单元移入Cache,假设我们移出了编号为10的主存单元。
接着,CPU再次访问编号为10的主存单元,则又引起了一次缺失。我们看到,如果在上一次删除时,删除其他的单元,则可以避免本次访问的缺失。
在现代计算机中,往往采用LRU(最近最少使用)的算法来进行Cache调度——可是,从上一个例子就能看出,这并不是最优的算法。
对于一个固定容量的空Cache和连续的若干主存访问请求,聪聪想知道如何在每次Cache缺失时换出正确的主存单元,以达到最少的Cache缺失次数。
【输 入】
输入文件第一行包含两个整数N和M(1<=M<=N<=100,000),分别代表了主存访问的次数和Cache的容量。
第二行包含了N个空格分开的正整数,按访问请求先后顺序给出了每个主存块的编号(不超过1,000,000,000)。
【输 出】
输出一行,为Cache缺失次数的最小值。
【样 例 】
输入数据 |
输出数据 |
解释 |
6 2 1 2 3 1 2 3 |
4 |
在第4次缺失时将3号单元换出Cache。 |
10 3 1 3 4 2 5 3 1 4 5 6 |
7 |
|
【思路】贪心,用next[i]数组保存第I个内存地址的下一次出现的位置,维护一个大根堆(我用优先队列实现= =刚好今天刚学)
要被换掉的这个数下一次出现的位置一定是越远越优
于是得到以下策略:
如果当前命中,就把容器容量+1,push进当前点的next[i]值//因为优先队列没办法找到当前值在队列中的位置= =想出了这种奇葩的方法,居然过了ORZ,正确性好像不大能保证
如果容器容量有剩余,直接push进去
如果需要交换出cache,弹出堆顶元素,并把当前点push进去
mark数组标记当前值是否在堆中
#include<cstdio> #include<queue> #include<cstring> using namespace std; int n,m,f[100000],next[100000],last[10000000],mark[10000000],i,ans; typedef pair<int,int> ele; int main() { // freopen("swap.in","r",stdin); // freopen("swap.out","w",stdout); scanf("%d%d",&n,&m); memset(mark,0,sizeof(mark)); memset(next,1,sizeof(next)); for (i=1;i<=n;i++){ scanf("%d",&f[i]); next[last[f[i]]]=i; last[f[i]]=i; } priority_queue<ele> q; for (i=1;i<=n;i++){ if (mark[f[i]]) { q.push(make_pair(next[i],f[i])); m++; continue;} if (q.size()<m) { q.push(make_pair(next[i],f[i])); ans++; mark[f[i]]=1; continue; } ele k=q.top(); q.pop(); mark[k.second]=0; q.push(make_pair(next[i],f[i])); mark[f[i]]=1; ans++; } printf("%d\n",ans); // getchar(); getchar(); }