1206: [HNOI2005]虚拟内存
Time Limit: 50 Sec Memory Limit: 162 MBSubmit: 142 Solved: 92
[ Submit][ Status]
Description
操作系统中一种重要的存储管理技术就是虚拟内存技术。操作系统中允许进程同时运行,也就是并行。每个进程都有其相对独立的数据块(进程运行的过程中将对其进行读写操作)。理想的情况下,这些数据块都应该存放在内存中,这样才能实现高效的读写操作。但事实上,内存的容量有限,每个进程只能把一部分数据放在内存中,为了解决这个矛盾,提出了虚拟内存技术。虚拟内存技术的基本原理是:对进程而言,内存空间是无限大的,进程可以随意地读写数据,而对操作系统内部而言,利用外存来模拟扩充的内存空间,进程要求访问某个内存单元时,交由操作系统处理,操作系统首先在内存中查找该单元是否存在,如果存在,查找成功,否则转入外存查找(一定存在于外存中)。就存储介质的物理性质而言,内存的访问速度相对于外存要快得多,因此对于每个进程来说操作系统应该把那些访问次数较多的数据存放在内存中,而把那些访问次数很少的数据放在外存中。如何选择内存中暂留的数据是一个很值得研究的问题,下面介绍一个内存管理中比较常用的算法:内存中的数据以页为基本存储单位,进程的读写操作都针对页来进行。实际内存空间被分割成n页,虚拟内存空间的页数往往要多得多。某一时刻,进程需要访问虚存编号为P的页,该算法的执行步骤如下: a. 首先在内存中查找,如果该页位于内存中,查找成功,转d,否则继续下面的操作; b. 寻找内存中是否存在空页(即没有装载任何数据页的页面),若有,则从外存中读入要查找页,并将该页送至内存中的空页进行存储,然后转d,否则继续下面的操作; c. 在内存中寻找一个访问次数最少的页面(如果存在多个页面的访问次数同时为最少,则选取最早读入数据进入内存的那个页面),从外存中读入要查找页,替换该页。 d. 结束所谓访问次数是指从当前页面进入内存到该时刻被访问的次数,如果该页面以前进入过内存并被其它页面替换,那么前面的访问次数不应计入这个时刻的访问次数中。你的任务是设计一个程序实现上述算法。测试数据将会提供m条读写内存的命令,每条命题提供要求访问的虚拟内存页的编号P。你的程序要求能够模拟整个m条命令的全部执行过程,所有的命令是按照输入的先后执行的,最开始的时候内存中的n页全为空。
Input
第1行为n<10000和m<1000000,分别表示内存页数和读写内存命令条数。接下来有m行,其中第i+1行有一个正整数Pi<=10^9,表示第i条读写内存命令需要访问的虚拟内存页的编号。
Output
仅包含一个正整数,表示在整个模拟过程中,在内存中直接查找成功的次数(即上面的算法只执行步骤a的次数)。
Sample Input
1
1
2
3
4
2
5
4
Sample Output
HINT
Source
【分析】:
此题用C++-STL的map库和set库可以轻松解决,思路为模拟法,详情请参见程序注解,详见代码1
同时也可以手写hash,一个不错的hash函数可以使效率提高不少,详见代码2
【代码1,纯STL】:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define MAXN 1000001
struct DATA_TYPES{int visit,data,when,where;};//对存储的数据而言的访问次数,数字,何时读入,存储位置
struct DATA_in_internal_storage{int visit,when;};//对于内存而言的访问次数,何时读入
DATA_in_internal_storage a[MAXN];//内存模拟数组
int N,M,ans=0;
int internal_storage_now=0;//内存当前存储位置最大值
map<int,int> hash;//某数字存在哪个地方
set<DATA_TYPES> internal_storage;//存储数据模拟载体
bool operator < (DATA_TYPES X,DATA_TYPES Y)//定义存储数据模拟载体的排序方式:如果存在多个数据的访问次数同时为最少,则选取最早读入数据进入内存的那个页面
{
if(X.visit==Y.visit) return X.when<Y.when;
return X.visit<Y.visit;
}
DATA_TYPES make(int visit,int data,int when,int where)
{
DATA_TYPES use;
use.visit=visit;
use.data=data;
use.when=when;
use.where=where;
return use;
}
int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
scanf("%d%d",&N,&M);
for(int i=1;i<=M;i++)
{
int data_input;
int where=0;//当前操作的执行存储位置
scanf("%d",&data_input);
if(where=hash[data_input])//a情况
{
DATA_TYPES use=make(a[where].visit,data_input,a[where].when,where);
internal_storage.erase(use);
a[where].visit++;
use.visit++;//将该数据访问次数加1
internal_storage.insert(use);
ans++;
}
else if(internal_storage_now<N)//b情况
{
where=++internal_storage_now;
a[where].visit=1;//添加数据
a[where].when=i;
DATA_TYPES use=make(1,data_input,i,where);
internal_storage.insert(use);
hash[data_input]=where;
}
else//c情况
{
DATA_TYPES use=*internal_storage.begin();//找到符合要求的将要删除的数据
where=use.where;
hash[use.data]=0;//删除数据
internal_storage.erase(use);
a[where].visit=1;//添加数据
a[where].when=i;
DATA_TYPES use1=make(1,data_input,i,where);
internal_storage.insert(use1);
hash[data_input]=where;
}
}
printf("%d\n",ans);
//system("pause");
return 0;
}
代码1效率:
/**************************************************************
Problem: 1206
Language: C++
Result: Accepted
Time:7348 ms
Memory:37600 kb
****************************************************************/
【代码2,手写hash法】
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<set>
using namespace std;
#define MAXN 1000001
#define MAX 1111091
struct DATA_TYPES{int visit,data,when,where;};
struct DATA_in_internal_storage{int visit,when;};
struct HASH{int data,where;};
DATA_in_internal_storage a[MAXN];
int N,M,ans=0;
int internal_storage_now=0,maxvis=0;
set<DATA_TYPES> internal_storage;
HASH hash[MAX];
bool operator < (DATA_TYPES X,DATA_TYPES Y)
{
if(X.visit==Y.visit) return X.when<Y.when;
return X.visit<Y.visit;
}
inline void add(int num,int where)
{
int key=(num)%MAX,tot=0;
key=(key+MAX)%MAX;
while(true)
{
if(hash[key].where) key=(key+1)%MAX;
else
{
hash[key].data=num;
hash[key].where=where;
break;
}
tot++;
maxvis=maxvis<tot?tot:maxvis;
}
}
inline int find(int num)
{
int key=(num)%MAX,tot=0;
key=(key+MAX)%MAX;
while(true)
{
if(hash[key].data==num) return hash[key].where;
else key=(key+1)%MAX;
tot++;
if(tot>maxvis) break;
}
return 0;
}
inline void erase(int num)
{
int key=(num)%MAX;
key=(key+MAX)%MAX;
while(true)
{
if(hash[key].data==num)
{
hash[key].where=0;
hash[key].data=0;
break;
}
else key=(key+1)%MAX;
}
}
inline DATA_TYPES make(int visit,int data,int when,int where)
{
DATA_TYPES use;
use.visit=visit;
use.data=data;
use.when=when;
use.where=where;
return use;
}
int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
scanf("%d%d",&N,&M);
for(int i=1;i<=M;i++)
{
int data_input;
int where=0;
scanf("%d",&data_input);
if(where=find(data_input))
{
DATA_TYPES use=make(a[where].visit,data_input,a[where].when,where);
internal_storage.erase(use);
a[where].visit++;
use.visit++;
internal_storage.insert(use);
ans++;
}
else if(internal_storage_now<N)
{
where=++internal_storage_now;
a[where].visit=1;
a[where].when=i;
DATA_TYPES use=make(1,data_input,i,where);
internal_storage.insert(use);
add(data_input,where);
}
else
{
DATA_TYPES use=*internal_storage.begin();
where=use.where;
erase(use.data);
internal_storage.erase(use);
a[where].visit=1;
a[where].when=i;
DATA_TYPES use1=make(1,data_input,i,where);
internal_storage.insert(use1);
add(data_input,where);
}
}
printf("%d\n",ans);
//system("pause");
return 0;
}
代码2效率:
/**************************************************************
Problem: 1206
Language: C++
Result: Accepted
Time:2900 ms
Memory:18032 kb
****************************************************************/