【题解】 CF507A Amr and Music
建议更改题目难度为:普及-
题意:
\(n\) 个物品,装进容量为 \(k\) 的背包(可以不装满),装进的物品数目要尽量多,输出装进物品的数量并输出它们的编号。
编号顺序任意排列,使用 Special Judge
。
解析:
这道题乍一看好像是01背包,但由于有了因为价值都为1、可以不装满的条件背包,所以每步的选择没有后效性且局部最优解的总和可以推出全局最优解,于是就可以使用贪心算法来解决。
大概步骤:
-
读入数据并将数据依物品的重量排序为单调递增形式。
-
判断背包剩余容量与背包外最小物品重量的大小,若背包剩余容量 \(\geqslant\) 背包外最小物品重量,则将此物品装入背包并更新背包剩余容量。重复执行此步骤直至背包剩余容量 \(<\) 背包外最小物品重量,此时解为最优。
-
输出背包内物品数量并按任意顺序输出背包内各物品编号。
实现:
因为需要输出物品编号,所以难以使用一维整形数组来进行数据存储与排序。我运用了结构体类型 priority_queue
(优先队列)来进行数据存储与排序,利用运算符重载来进行自定义排序。
但是,这道题输出要求先输出背包内物品的数量,就导致我们无法边判断边输出浪费了大把时间,于是我使用了 stack
容器来存储各物品编号,在判断完成后再进行输出。
代码:
(437ms,8KB)
#include<bits/stdc++.h>
using namespace std;
struct NODE{
int w,num;
bool operator <(const NODE&v)const{
return w>v.w;
//运算符重载自定义优先队列排序为依重量降序
}
};
priority_queue<NODE>c;
stack<int>o;
int n,k,ans=0;
int main()
{
scanf("%d%d",&n,&k);
for(int i=1,ci;i<=n;i++){
scanf("%d",&ci);
c.push({ci,i});
}
for(int i=1;i<=n;i++)
if(!c.empty()){
NODE h=c.top();
c.pop();
if(k>=h.w){
o.push(h.num);//存入物品编号数据
k-=h.w;
}
else
break;
}
else
break;
printf("%d\n",o.size());
while(!o.empty())
{
printf("%d ",o.top());
o.pop();
}
return 0;
}