【BZOJ 3117] [NOI1999】メモリアロケーション(STL)
フェイス質問
メモリは、プログラムが割り当てられるメモリ内で実行されている、コンピュータの重要な資源の一つです。古典的なメモリ割り当て処理が行われます。
1.基本ユニット、識別などの固定された整数と、各メモリセルとメモリセルとメモリは、アドレスと呼ばれます。0が連続的開始アドレスから配置され、隣接するユニットのメモリアドレスは、論理的に連続であると考えられます。私たちは、私は連続したメモリユニットは、アドレス長の最初のアドレスはI Sシートであると呼ばれているのアドレスから開始します。
動作中2.処理に必要なメモリの数、各プロセスが時間Tに対する要求を有し、MおよびランタイムP.を必要とされるメモリセルの数 実行時に(即ち、時間Tの開始、終了時刻T + P)Mメモリセルによって占有され、もはや別のプロセスで使用することができるでP。
そこM時間単位Tを適用するプロセスであり、実行時間は、次に、Pであると仮定3。
- 時間T M-チップフリーアドレスのメモリ長がある場合、システムは、プロセスに割り当てられ、これらのM単位をアイドル。長さMのチップアドレスアイドル複数の場合、システムは、最初の空きアドレスがプロセスに割り当てられていることを最小個に取り組みます。
- Tは一枚M存在しないアイドルアドレスの時間の長さである場合、プロセスは待ち行列につながれています。HOLキュー待ち処理において、であれば任意の時点で、Mチップフリーアドレスの長さがあるので、システムはすぐに削除キューを処理し、そしてそれのためにメモリを割り当てます。メモリ割り当て処理が実行されることに注意してください、プロセスが最優先の待ちキューの先頭のチームであるチームのヘッド・プロセスが処理される前に、他のプロセスがキューにすることはできません。
今、与えられたデータ系列は、プロセス、システムの割り当てメモリをシミュレートするプログラムを書き込む処理を説明しました。
分析
set
メンテナンスメモリ、各要素は、連続した空きメモリとして、間隔です。あなたは間隔のエンドポイントを変更する必要があるときに、メモリのセクションを割り当てます。あなたが範囲に新たに追加を挿入したい、との間隔が連続左右するだけでなく、必要であればマージするためにリリースメモリ。なぜなら、特定の不連続区間挿入前に、これだけの複雑さを2回マージする必要が\(O(\)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));
}
}
暴力はセット全体を横断したときに空きメモリを検索し、複雑さ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("\n");
}
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\n%d\n",last,inq_cnt);
}