贪心算法,你人够贪就会做。贪心就是通过部分最优解来推出全局最优解,可以理解为在每个子阶段都取当前最优解,到最后合并的时候的解是全局最优解。
【深基12.例1】部分背包问题
解析:
题目给出体积和价值,需要求背包最大容积下的最大价值,物品可拆分,显然是贪心算法。那么如何做到局部最优解?很简单,当然是每次都取最大价值的放进去背包,大错特错!正解应该是每次都取最大的性价比(性价比=价值/体积),如果小于背包当前所剩容积就整个放进去,否则拿部分放进背包。
#include <bits/stdc++.h>
#define MOD 1000000007
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
int n,t;
double ans;
struct node {
int m,v;
double val;
} a[105];
//按性价比排序
bool cmp1(node a,node b) {
return a.val>b.val;
}
int main() {
cin>>n>>t;
for(int i=1; i<=n; i++) {
cin>>a[i].m>>a[i].v;
a[i].val=a[i].v*1.0/a[i].m;//计算性价比
}
sort(a+1,a+n+1,cmp1);
for(int i=1; i<=n; i++) {
if(a[i].m<=t) { //整个放进背包
ans+=a[i].v;
t-=a[i].m;
}
else {//分割部分放进背包
ans+=(t*1.0/a[i].m)*a[i].v;
break;
}
}
printf("%.2f",ans);
return 0;
}
排队接水
解析:
题目需要我们求平均等待时间最短的排队顺序及平均等待时间,很简单,就是先由打水时间短的打水,依次往下,所以我们需要按照打水时间进行升序排序,并计算这些人等待时间之和。
#include <bits/stdc++.h>
#define MOD 1000000007
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
int n;
double ans;
struct node {
int id,t;
} a[1005];
//按时间进行升序
bool cmp1(node a,node b) {
return a.t<b.t;
}
int main() {
double ans=0.0;
cin>>n;
for(int i=1; i<=n; i++) {
cin>>a[i].t;
a[i].id=i;//赋予id用于输出第一行
}
sort(a+1,a+n+1,cmp1);
for(int i=1; i<=n; i++) {
cout<<a[i].id<<" ";
ans+=a[i].t*1.0*(n-i);//等待时间之和
}
cout<<endl;
printf("%.2f",ans*1.0/n);
return 0;
}
凌乱的yyy / 线段覆盖
解析:只要结束时间和开始时间靠的比较近即可,所以我们只需要对结束时间排序,如果该结束时间的起始时间与上一个重叠则遍历下一个,否则就ans++并更新终止时间。
#include <bits/stdc++.h>
#define MOD 1000000007
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
int n;
double ans;
struct node {
int a,b;
} p[1000005];
//按照结束时间进行升序排序,只要结束时间和下一个起始时间不撞就好了
bool cmp1(node x,node y) {
return x.b<y.b;
}
int main() {
int ans=0;
cin>>n;
for(int i=1; i<=n; i++)
cin>>p[i].a>>p[i].b;
sort(p+1,p+1+n,cmp1);
int m=0;
for(int i=1; i<=n; i++) {
if(p[i].a>=m) {//符合情况(起始时间在上一个结束时间的后面)
ans++;
m=p[i].b;//更新结束时间
}
}
cout<<ans;
return 0;
}
蓝桥杯比赛已结束,即使已经知道结果差强人意,也不应该就此颓废,我得调整心态、收拾心情、继续前行。