贪心算法(以Length of Bundle Rope和Monster为例)
一个字,贪。不管任何后果的贪(貌似也不是)。就是那种,说不出来的那种,贪。
干说肯定说不出啥,那就拿个例题
Length of Bundle Rope
大意就是这个人要拿绳子把箱子两个两个捆在一起这样才能固定(当两个箱子捆在一起就可以当做一个新的箱子来看了),所以每两个箱子就需要一根绳子,这个捆箱子的方式都是横着来捆的, 也就是说捆两个箱子的绳子长度就是两个箱子的长度,让我们怎么捆能让最后需要的绳子长度最小。
下面是代码,亲手注释(看不看得懂就不知道了,希望我这篇阅读理解你看得懂)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
int a[1111];
priority_queue<int , vector<int>, greater<int> >q;
//这是一个优先队列,将push进去的值不是按先进先出的顺序pop(),而是按照谁的数值越小谁先pop().(或者top)
//不知道的可以先搜一下stl的priority_queue,先了解一下不是坏事
int main(){
int t;
scanf("%d", &t);//读入t
while(t--){//t组输入
int n;
scanf("%d", &n);//输入n
for(int i=0;i<n;i++){
scanf("%d", &a[i]);
q.push(a[i]);
//读入n个数字并push进优先队列
}
int sum=0;//让绳子等于0,开始操作了(要是只有一个箱子就不需要绳子,因为一个箱子就是固定的)
while(!q.empty()){
int l, r;//前面两个最小的数,r可能没有因为如果是一个箱子的话。
l=q.top();//先把前面的左边那个箱子长度给拿到
q.pop();//就可以把队列里的那个长去掉了
if(q.empty())break;//如果没有了就说明这个就是最后那1个箱子直接退出,否则往下进行
r=q.top();//拿到最前面右边那个数
q.pop();//然后去掉优先队列里的
sum+=l+r;//把两个箱子长困到一起,绳子长度就是l+r,加到总绳子长里
q.push(l+r);//将新箱子的长度push进优先队列
}
printf("%d\n", sum);//输出绳子总长
}
return 0;
}
总的来说这一题,我们贪的就是每个箱子最短的长,每组合两个个箱子,就要判断一次最短箱子是哪两个,然后再组合两个最短箱子,以此类推。(谁知道你组合出来的箱子是不是比队列前面最小的箱子大)
再来一个相互影响的贪心
Monster
题目大意就是有t个样例,每个样例先给你一组怪物的数量n和v11(主人公)的攻击力atk。接下来会给你怪物的血量monhp和怪物的攻击力monatk,v11无限血(别问,问就是开挂)。v11被怪兽围攻,然后他每次只能攻击一个怪兽,让怪兽的monhp减去他的攻击力atk,当怪的hp<=0之后怪物就不会对他攻击了(挂了)。问的是按什么顺序打怪能让v11减去的血量最少(都开挂了还这么矫情)。
首先我们要知道,当v11在打一个怪时,其他的怪也在打他(问就是开挂狗该打),所以这里我们贪的有点不一样,我们贪的是这一只怪的攻击力乘另一只怪能在v11手上存活的次数,因为这样这只怪才能在别的怪吸引火力时疯狂输出,所以我么排序的时候的cmp就这么写具体见一下代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
struct monster{
int hp;//怪物的血量
int atk;//怪物的攻击力
int times;//在v11手上存活的次数
}mon[11111];
bool cmp(monster p1, monster p2){
return p1.atk*p2.times > p2.atk*p1.times;//sort的特殊比较函数
//让这个怪乘零一个怪的存货次数大的放前面(对v11的威胁更大,我们要帮挂狗)
}
int main(){
int t, k=1;//t组样例,第k个案例
scanf("%d", &t);
while(t--){
int n, atk;//n个怪,v11的攻击atk
long long atk_sum=0;//现存的所有怪的攻击力的和
scanf("%d %d", &n, &atk);
for(int i=0;i<n;i++){
scanf("%d %d", &mon[i].hp, &mon[i].atk);//输入怪物血量和攻击力
mon[i].times=ceil(mon[i].hp*1.0/atk);//获取这个怪在v11的手上存活的次数
atk_sum+=mon[i].atk;//攻击总和加上
}
sort(mon, mon+n, cmp);//按上面提到的条件排序
long long sum=0;//v11受到的总伤
for(int i=0;i<n;i++){
sum+=atk_sum*mon[i].times;//这个怪争取到的时间*所有怪的伤害总和加到对v11的总伤害里
atk_sum-=mon[i].atk;//死掉了一只怪,少了一只怪的战力
}
printf("Case #%d: ", k++);//格式
printf("%lld\n", sum);
}
return 0;
}
贪心就是要找到题意所给到的所有例子能满足的当前的最优计算方式, 可能会忽略某些局部利益,但是正因为这样,这类算法才会被统称为贪心算法
最后
————————————————做人不要太贪,有姑姑就好————————————————