打包(pack.cpp/in/out) 1S/128M
N个圆柱形的盒子,底面积均相同,高度不同。每个盒子的高度都是2的非负次幂,即2^i(i= 0, 1, 2, …)。每个盒子各有一个价值。
有若干个集装箱用来打包这N个盒子。集装箱也是圆柱形的,底面积稍比盒子大一点,也就是说,盒子在集装箱里只能叠放,不能并列放。集装箱的高度也是2的非负次幂,即2^i(i= 0, 1, 2, …)。
一个集装箱必须装满盒子,才能安全运输。例如,有5个盒子,高度和价值分别是(第1个整数是高度的指数,第2个整数是价值):
1 3
1 2
3 5
2 1
1 4
有2个集装箱,高度分别是2^1和2^2,那么有3种方案用2个盒子装满2个集装箱,分别得到总价值为3,4,5。有1种方案用3个盒子装2个集装箱,得到总价值为9。
但是这些盒子却无法装满一个高度为2^5的集装箱。
给出盒子和集装箱的信息,求装满所有集装箱的总价值最小的方案。
输入格式:
第1行:1个整数N(1 <= N <= 10000)表示盒子的数量
接下来N行,每行2个整数,分别表示盒子高度的指数和价值,高度不超过1000,价值不超过10000
接下来1行,1个整数Q,表示集装箱的类型数
接下来Q行,每行2个整数,第1个表示这种集装箱的高度(指数),第2个表示这种集装箱的数量
集装箱总数不超过5000,每个集装箱的高度(指数)不超过1000
输出格式:
如果所给盒子能装满全部集装箱,输出最小的总价值。如果不能,输出-1。
输入样例
5
1 3
1 2
3 5
2 1
1 4
2
1 1
2 1
输出样例
3
注意到这里的高度可以直接用指数来表示,然后就考虑判定是否有解的情况
对于高度为0的集装箱,所有高度为0的盒子的个数必定要大于集装箱的个数,也就是说如果高度为0的盒子的个数小于高度为0的集装箱的个数其实是无解的
由于题目只要求装满集装箱,并不关心每个集装箱里装的是什么样的盒子,我们用cnth[i]记录高度为i个盒子个数,cntx[i]记录高度为i的集装箱个数
cnth[i]除了题目中给出的高度为i的盒子总数,我们还可以考虑将两个高度为i-1的盒子合成一个高度为i的盒子,每找到这样一对cnth[i]++
所以对于每一个高度都应该先计算下其cnth[i]然后判断cnth[i]与cntx[i]的大小关系
由于要求找到最优解,我们只需在判断是否有解的时候顺便更新答案,具体步骤如下:
1.第k步时,若非无解情况,则选前cntx[k-1]个价值最小的盒子;
2.第k步时,剩下cnth[k-1]-cntx[k-1]个盒子,则把它从小到大排序后,让第2*I-1与2*I(I>=1)个盒子结合成一个尺寸为k的大盒子。
很好看出,这就是一个贪心原则
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=20005;
inline void _read(int &x){
char t=getchar();bool sign=true;
while(t<'0'||t>'9')
{if(t=='-')sign=false;t=getchar();}
for(x=0;t>='0'&&t<='9';t=getchar())x=x*10+t-'0';
if(!sign)x=-x;
}
struct wk{
int h,t;
bool operator<(const wk& u)const{
return h<u.h;
}
}s[maxn];
int n,Q,cnth[maxn],cur,v[maxn],ans,tot,last[maxn],Next[maxn];
void insert(int Size,int val){//这里用链表保存不同高度的盒子
cnth[Size]++,v[++tot]=val;//注意只有相同高度的盒子才在同一条链上
Next[tot]=last[Size];
last[Size]=tot;
for(int i=last[Size];i&&Next[i];i=Next[i])
if(v[i]>v[Next[i]])swap(v[i],v[Next[i]]);
}
void update(int Size){
while(cur<Size){
while(cnth[cur]>=2){
cnth[cur]-=2;
int p=last[cur];
insert(cur+1,v[p]+v[Next[p]]);
last[cur]=Next[Next[p]];
}
cur++;
}
}
void solve(){
for(int i=1;i<=Q;i++){
while(s[i].t>0){
int temp=s[i].h;
if(cur<temp)update(temp);
if(cnth[cur]>0){
int p=last[temp];
ans+=v[p];
last[temp]=Next[p];
cnth[cur]--;
s[i].t--;
}
else{
puts("-1");
return ;
}
}
}
cout<<ans;
}
int main(){
_read(n);
int i,j,x,y;
for(i=1;i<=n;i++){
_read(x);_read(y);
insert(x,y);
}
_read(Q);
for(i=1;i<=Q;i++){
_read(s[i].h);_read(s[i].t);
}
sort(s+1,s+1+Q);
solve();
}