问题描述:
说有一台机器,上面有m个储存空间。然后有n个请求,第i个请求计算时需要占R[i]个空间,储存计算结果则需要占据O[i]个空间(其中 O[i]<R[i])。问怎么安排这n个请求的顺序,使得所有请求都能完成。你的算法也应该能够判断出无论如何都不能处理完的情况。
题解:
假设可以满足所有请求,并且处理请求的顺序是:r1,r2,……r(n-1),r(n),那么存储完所有的请求结果后,剩余的存储空间为L= m-∑O[i]。
如果假设成立,必须满足:针对请求r(n),一定有L+O[r(n)]>=R[r(n)]。同理,针对r(n-1),一定有
L+O[r(n)] + O[r(n-1)] >= R[r(n-1)],依次类推。于是,证明假设成立就转化为:针对假设中的每一个请求r(i),都有L+∑O[r(n-j)]>=R[r(i)],其中i>=j>=0。相应的,原问题也就转化成从寻找这样的r(i)。
既然如此,从寻找r(n)开始,这时候有n个选择(R[1]~R[n]),那么选择哪一个呢?如上所说,我们选择的原则是满足L+O[r(n)]>=R[r(n)],即L>=R[r(n)]-O[r(n)]。所以将所有的选择按照R[r(n)]-O[r(n)]从小到大排序,每次选择时试探R[r(n)]-O[r(n)]最小的值,如果最小值都不能满足,那么已经证明假设不成立,否则继续探测n-1,n-2……1,直到出现不能满足的情况,或者证明假设成立。
时间复杂度:nlogn(事先的排序)+n
#include <iostream>
#include<string>
#include<cmath>
#include<queue>
#include<algorithm>
#include<functional>
#include<numeric>
using namespace std;
//const int N=8;
//const int M=50;
//int request[]={10,15,23,20,6,9,7,16};
//int occ[]={2,7,8,4,5,8,6,8};
const int N=2;
const int M=14;
int request[]={10,8};
int occ[]={5,6};
struct Node{
int request;
int occ;
int idx;
};
Node nodes[N];
int cmp(const Node& a,const Node& b){
return a.request-a.occ<b.request-b.occ;
}
void func(){
for(int i=0;i<N;++i){
nodes[i].request=request[i];
nodes[i].occ=occ[i];
nodes[i].idx=i;
}
sort(nodes,nodes+N,cmp);
int L=accumulate(occ,occ+N,0);
//先分配的是最序列中最后一个
for(int i=0;i<N;++i){
if(L+nodes[i].occ<nodes[i].request){
cout<<"cannot allocate"<<endl;
return;
}
L=L-nodes[i].occ;
}
cout<<"may allocate,allocate seq is:"<<endl;
for(int i=N-1;i>=0;--i)
cout<<nodes[i].idx<<" ";
cout<<endl;
}
int main()
{
func();
system("pause");
return 0;
}