[BZOJ 3117] [NOI1999]内存分配(STL)

[BZOJ 3117] [NOI1999]内存分配(STL)

题面

内存是计算机重要的资源之一,程序运行的过程中必须对内存进行分配。 经典的内存分配过程是这样进行的:

1.内存以内存单元为基本单位,每个内存单元用一个固定的整数作为标识,称为地址。地址从0开始连续排列,地址相邻的内存单元被认为是逻辑上连续的。我们把从地址i开始的s个连续的内存单元称为首地址为i长度为s的地址片。

2.运行过程中有若干进程需要占用内存,对于每个进程有一个申请时刻T,需要内存单元数M及运行时间P。在运行时间P内(即T时刻开始,T+P时刻结束),这M个被占用的内存单元不能再被其他进程使用。

3.假设在T时刻有一个进程申请M个单元,且运行时间为P,则:

  • 若T时刻内存中存在长度为M的空闲地址片,则系统将这M个空闲单元分配给该进程。若存在多个长度为M个空闲地址片,则系统将首地址最小的那个空闲地址片分配给该进程。
  • 如果T时刻不存在长度为M的空闲地址片,则该进程被放入一个等待队列。对于处于等待队列队头的进程,只要在任一时刻,存在长度为M的空闲地址片,系统马上将该进程取出队列,并为它分配内存单元。注意,在进行内存分配处理过程中,处于等待队列队头的进程的处理优先级最高,队列中的其它进程不能先于队头进程被处理。

现在给出一系列描述进程的数据,请编写一程序模拟系统分配内存的过程。

分析

用一个set维护内存,每个元素是一个区间,表示连续的空闲内存。分配一段内存的时候需要修改区间端点。而释放内存的时候除了要将一个新的区间插入之外,如果和左边和右边的区间是连续的,还需要合并。因为插入之前区间一定不连续,所以只需要合并2次,复杂度(O(log n))

typedef set< pair<int,int> >sp;
typedef sp::iterator spi;
sp mem;
void new_mem(spi it,int sz){
	int l=it->first,r=it->second;
	mem.erase(it);
	if(l+sz<=r){
		mem.insert(make_pair(l+sz,r));
	}
}
void free_mem(pair<int,int>x) {
	if(mem.empty()){
		mem.insert(x);
		return; 
	}
	 spi pre=mem.lower_bound(x);
	 if(pre!=mem.begin()) pre--;
	 if(pre->second+1==x.first){
	 	int newl=pre->first;
	 	mem.erase(pre);
	 	pre=mem.insert(make_pair(newl,x.second)).first;
	 	//insert返回插入的位置 
		//利用insert的返回值,找到合并后的区间,方便第二次合并 
	 }else pre=mem.insert(x).first;
	 spi nex=mem.upper_bound(x);
	 if(nex!=mem.end()&&x.second+1==nex->first){
	 	int newl=pre->first;
	 	int newr=nex->second;
	 	mem.erase(pre);
	 	mem.erase(nex);
	 	mem.insert(make_pair(newl,newr));
	 }
}

查找空闲内存的时候暴力遍历整个set,复杂度O(能过)。


priority_queue维护的当前正在运行的进程,按照结束时间从小到大排序。

struct task {
	ll st;//开始时间
	ll ed;//结束时间
	int space;//内存大小
	pair<int,int>p;//占用的内存区间
	task() {

	}
	task(ll _st,ll _ed,int _space,pair<int,int>_p) {
		st=_st;
		ed=_ed;
		space=_space;
		p=_p;
	}
	friend bool operator < (task p,task q) {
		return p.ed>q.ed;
	}
};
priority_queue<task>now_run;

等待队列直接用一个queue维护就好了。


每当一个进程请求内存的时候。先把正在运行的进程中,结束时间<请求时间的内存释放。等同一时刻结束的进程结束后,再处理等待队列。然后尝试把当前进程添加,如果空闲内存足够,则直接分配内存。否则加入等待队列。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<utility>
#define maxm 10000
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
int n;
int cnt;
struct oper {
	ll t;
	int m;
	ll p;
} a[maxm+5];

typedef set< pair<int,int> >sp;
typedef sp::iterator spi;
sp mem;
void new_mem(spi it,int sz){
	int l=it->first,r=it->second;
	mem.erase(it);
	if(l+sz<=r){
		mem.insert(make_pair(l+sz,r));
	}
}
void free_mem(pair<int,int>x) {
	if(mem.empty()){
		mem.insert(x);
		return; 
	}
	 spi pre=mem.lower_bound(x);
	 if(pre!=mem.begin()) pre--;
	 if(pre->second+1==x.first){
	 	int newl=pre->first;
	 	mem.erase(pre);
	 	pre=mem.insert(make_pair(newl,x.second)).first;
	 	//insert返回插入的位置 
		//利用insert的返回值,找到合并后的区间,方便第二次合并 
	 }else pre=mem.insert(x).first;
	 spi nex=mem.upper_bound(x);
	 if(nex!=mem.end()&&x.second+1==nex->first){
	 	int newl=pre->first;
	 	int newr=nex->second;
	 	mem.erase(pre);
	 	mem.erase(nex);
	 	mem.insert(make_pair(newl,newr));
	 }
}
pair<int,int> find_mem(int sz){
	for(spi it=mem.begin();it!=mem.end();it++){
		int l=it->first,r=it->second;
		if(r-l+1>=sz){
			new_mem(it,sz);
			return make_pair(l,l+sz-1);
		}
	}
	return make_pair(-1,-1);
}
void print_mem(){
	for(spi it=mem.begin();it!=mem.end();it++){
		int l=it->first,r=it->second;
		printf("[%d,%d] ",l,r);
	}	
	printf("
");
} 

struct task {
	ll st;
	ll ed;
	int space;
	pair<int,int>p;
	task() {

	}
	task(ll _st,ll _ed,int _space,pair<int,int>_p) {
		st=_st;
		ed=_ed;
		space=_space;
		p=_p;
	}
	friend bool operator < (task p,task q) {
		return p.ed>q.ed;
	}
};
priority_queue<task>now_run;
queue<int>now_wait;
void pop_wait(ll tim) {
	while(!now_wait.empty()) {
		int id=now_wait.front();
		pair<int,int>tmp=find_mem(a[id].m);
		if(tmp.first!=-1) {
			now_run.push(task(tim,tim+a[id].p,a[id].m,tmp));
			now_wait.pop();
		} else break;
	}
}

ll last=0;
void free_task(ll tim) {
	while(!now_run.empty()&&now_run.top().ed<=tim) {
		task tmp=now_run.top();
		free_mem(tmp.p);
		last=max(last,tmp.ed);
		now_run.pop();
		if(now_run.empty()||now_run.top().ed!=tmp.ed) pop_wait(tmp.ed);//等同一时刻结束的进程释放后,再处理等待的 
	}
}

int inq_cnt=0;
void add_task(int id) {
	free_task(a[id].t);
	pair<int,int>tmp=find_mem(a[id].m);
	if(tmp.first!=-1) {
		now_run.push(task(a[id].t,a[id].t+a[id].p,a[id].m,tmp));
	} else {
		inq_cnt++;
		now_wait.push(id);
	}
}

int main() {
	int u,v,w;
	scanf("%d",&n);
	while(scanf("%d %d %d",&u,&v,&w)!=EOF) {
		if(u==0&&v==0&&w==0) break;
		cnt++;
		a[cnt].t=u;
		a[cnt].m=v;
		a[cnt].p=w;
	}
	mem.insert(make_pair(0,n-1));
	for(int i=1; i<=cnt; i++) {
		add_task(i);
	}
	free_task(INF);
	printf("%lld
%d
",last,inq_cnt);
}
原文地址:https://www.cnblogs.com/birchtree/p/12043579.html