「 「 「基础算法 」 」 」第 2 2 2章 贪心算法
目录:
A.奶牛晒衣服
B.雷达装置
C.畜栏预定
D.国王游戏
A . A. A. 例题 1 1 1 奶牛晒衣服
分析:
干衣所需时间是取决于最后一件烘干的衣物的所需时间
所以我们每次对剩余时间最多的衣物用烘干机
对于剩余时间最多 我们可以用一个大根堆维护 s o r t sort sort会超时
CODE:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define reg register
using namespace std;
priority_queue<int> f; //大根堆
int n,a,b,x,t;
int main()
{
scanf("%d%d%d",&n,&a,&b);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
f.push(x);
}
t+=a; //单独处理第一天
int k=f.top();
f.pop();
k-=b;
f.push(k);
while(1)
{
int k=f.top();
f.pop();
if(k-t<=0){
printf("%d",t/a); //总量/单价=数量
return 0;
}
k-=b; //继续贪心
f.push(k);
t+=a;
}
return 0;
}
B . B. B. 例题 2 2 2 雷达装置
分析:
如果小岛能被探测 则用结构体记录可探测第 i i i个小岛的雷达中 x x x的最小值 ( l ) (l) (l)及最大值 ( r ) (r) (r) 即区间
并将区间数组按 r r r排序 这样可以按 x x x从小往大遍历
当雷达不够了 则需添加雷达 并重新赋值
注意用勾股定理求距离 最小值 x − d i s x-dis x−dis 最大值 x + d i s x+dis x+dis
CODE:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cmath>
#define reg register
using namespace std;
int n,d,ans=1;
struct node{
double l,r;
}a[1005];
bool cmp(node x,node y){
return x.r<y.r;}
int main()
{
scanf("%d%d",&n,&d);
for(int i=1;i<=n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
if(d<y){
printf("-1");
return 0;
}
int dis=sqrt(d*d-y*y); //求距离
a[i].l=x-dis;a[i].r=x+dis; //求区间
}
sort(a+1,a+n+1,cmp);
int x=a[1].r;
for(int i=2;i<=n;i++)
if(x<a[i].l) x=a[i].r,ans++; //雷达不够就添加 赋值
printf("%d",ans);
return 0;
}
C . C. C. 例题 3 3 3 畜栏预定
分析:
贪心策略:
将牛的左端点和右端点 分别开结构体存储 再将它们排序
如果牛棚的右端点没有牛棚 就添加一个
然后找后面左端点第一个比该右端点大的 放上与该右端点牛相同的牛棚
顺带更新一下 a n s ans ans即可.
CODE:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cmath>
#define reg register
using namespace std;
const int N=5e5+5;
int n,num,ans[N];
struct node{
int val,id;
}a[N],b[N];
bool cmp(node x,node y){
return x.val<y.val;}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].val,&b[i].val);
a[i].id=b[i].id=i;
}
sort(a+1,a+n+1,cmp);
sort(b+1,b+n+1,cmp);
for(int i=1,j=1;i<=n;i++)
{
if(j<=n) j++;
if(!ans[b[i].id]) ans[b[i].id]=++num; //放新牛棚
while(a[j].val<=b[i].val&&j<=n) j++; //向后枚举
ans[a[j].id]=ans[b[i].id]; //更新答案
}
printf("%d\n",num);
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]);
return 0;
}
D . D. D. 例题 4 4 4 国王游戏
分析:
考虑交换相邻两个人
交换前:
那么 第 i i i位的权值就是 : ( ! a i − 1 ) / b i :(!a_{i-1})/b_i :(!ai−1)/bi ( ! (! (!表阶乘 ) ) )
第 i + 1 i+1 i+1位的权值同理 : ( ! a i ) / b i + 1 :(!a_i)/b_{i+1} :(!ai)/bi+1
其中的最大值 m a x 1 = m a x ( ( ! a i − 1 ) / b i , ( ! a i ) / b i + 1 ) max1=max((!a_{i-1})/b_i,(!a_i)/b_{i+1}) max1=max((!ai−1)/bi,(!ai)/bi+1)
交换后
第 i + 1 i+1 i+1位的权值变为 : ( ! a i − 1 ) / b i + 1 :(!a_{i-1})/b_{i+1} :(!ai−1)/bi+1
第 i i i位权值变为 : ( ! a i − 1 ) ∗ a i + 1 / b i :(!a_{i-1})*a_{i+1}/b_i :(!ai−1)∗ai+1/bi
最大值 m a x 2 = m a x ( ( ! a i − 1 ) / b i + 1 , ( ! a i − 1 ) ∗ a i + 1 / b i ) max2=max((!a_{i-1})/b_{i+1},(!a_{i-1})*a_{i+1}/b_i) max2=max((!ai−1)/bi+1,(!ai−1)∗ai+1/bi)
对比一下 ( ! a i − 1 ) / b i (!a_{i-1})/b_i (!ai−1)/bi肯定是小于 ( ! a i − 1 ) ∗ a i + 1 / b i (!a_{i-1})*a_{i+1}/b_i (!ai−1)∗ai+1/bi的 如果 m a x 1 < m a x 2 max1<max2 max1<max2 则说明:
( ! a i ) / b i + 1 < ( ! a i − 1 ) ∗ a i + 1 / b i (!a_i)/b_{i+1}<(!a_{i-1})*a_{i+1}/b_i (!ai)/bi+1<(!ai−1)∗ai+1/bi
化简可得: a i ∗ b i < a i + 1 ∗ b i + 1 a_i*b_i<a_{i+1}*b_{i+1} ai∗bi<ai+1∗bi+1
注意高精
CODE:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cmath>
#define reg register
using namespace std;
const int N=10005;
typedef long long ll;
int n,now[N],ans[N],minn[N],ansn,nown,minx;
struct node{
int l,r,lr; //左手,右手,左右手乘积
}a[N];
bool cmp(node x,node y){
return x.lr<y.lr;}
void Pai(int x) //累乘函数 高精
{
for(reg int i=1;i<=nown;i++)
now[i]*=x;
for(reg int i=1;i<=nown;i++)
{
now[i+1]+=now[i]/10;
now[i]%=10;
if(i==nown&&now[i+1]!=0) nown++;
}
}
void dev(int x) //高精除
{
memset(minn,0,sizeof(minn));
minx=0;
int val=0;
for(reg int i=nown;i>0;i--)
{
val=val*10+now[i];
minn[i]=val/x;
if(minx==0&&minn[i]!=0) minx=i;
val%=x;
}
for(reg int i=1;i<=minx;i++)
{
minn[i+1]+=minn[i]/10;
minn[i]%=10;
if(i==minx&&minn[i+1]!=0) minx++;
}
}
bool check()
{
if(ansn<minx) return true;
if(minx<ansn) return false;
for(reg int i=ansn;i>0;i--)
{
if(minn[i]>ans[i]) return true;
if(minn[i]<ans[i]) return false;
}
return false;
}
void swp(){
for(int i=1;i<=minx;i++)
ans[i]=minn[i];
ansn=minx;
}
int main()
{
scanf("%d",&n);
for(reg int i=0;i<=n;i++)
{
scanf("%d%d",&a[i].l,&a[i].r);
a[i].lr=a[i].l*a[i].r;
}
sort(a+1,a+n+1,cmp);
nown=1;now[1]=1;
for(reg int i=1;i<=n;i++)
{
Pai(a[i-1].l);
dev(a[i].r); //贪心策略
if(check()) swp();
}
for(int i=ansn;i>0;i--)
printf("%d",ans[i]);
return 0;
}