LOJ 一本通提高篇1.1贪心算法 例题

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-2 17:13   2660   0

复习时食用,会比较简略。


目录

#10000. 「一本通 1.1 例 1」活动安排

#10001. 「一本通 1.1 例 2」种树

#10002. 「一本通 1.1 例 3」喷水装置

#10003. 「一本通 1.1 例 4」加工生产调度

#10004. 「一本通 1.1 例 5」智力大冲浪


#10000. 「一本通 1.1 例 1」活动安排

题目

题目大意

有n个活动,每个活动i都有起始时间s_i和结束时间f_i。

若区间[s_i,f_i)与区间[s_j,f_j)不相交,则活动i与活动j相容。

选择出由互相兼容的活动组成的最大集合。

1<=n<=1000。

题目分析

贪心。

将每个活动的结束时间从小到大排序。

每次选择结束时间最早的开始时间大于等于结束时间的活动。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

struct node{int s,f;}a[1010];
int cmp(node x,node y)
{
 if(x.f==y.f) return x.s<y.s;
 else return x.f<y.f;
}

int main()
{
 int n; scanf("%d",&n);
 for(int i=1;i<=n;i++) scanf("%d%d",&a[i].s,&a[i].f);
 sort(a+1,a+1+n,cmp);//按结束时间从小到大排序
 int ans=1,end=a[1].f-1;
 for(int i=2;i<=n;i++)
 {
  if(a[i].s>end) { ans++; end=a[i].f-1; }
 }
 printf("%d",ans);
 return 0;
}

#10001. 「一本通 1.1 例 2」种树

题目

题目大意

某条街被划为n条路段,每个路段可以种一棵树。

给出了h组建议,希望在路段b到e之间至少要种t棵树。

问至少要种多少棵树。

30%的数据满足0<n<=1000,0<h<=500;

100%的数据满足0<n<3*10^4,h<=5000,0<b<=e<=3*10^4,t<=e-b+1。

题目分析

贪心。

跟上一题有异曲同工之妙。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

bool b[30010];
struct node{int b,e,t;}a[5010];
int cmp(node x,node y) { return x.e<y.e; }

int main()
{
 int n,h; scanf("%d%d",&n,&h);
 memset(b,false,sizeof(b));
 for(int i=1;i<=h;i++)
 {
  scanf("%d%d%d",&a[i].b,&a[i].e,&a[i].t);
 }
 sort(a+1,a+1+h,cmp);//按种树路段的末尾排序
 int ans=0;
 for(int i=1;i<=h;i++)
 {
  int s=0;//先找这一段路已有的树
  for(int j=a[i].b;j<=a[i].e;j++) if(b[j]) s++;
  if(s<a[i].t)//还没有种够
  {
   for(int j=a[i].e;j>=a[i].b;j--)
   {
    if(b[j]==false)//这个位置没有树就种啊
    {
     s++; b[j]=true; ans++;
     if(s==a[i].t) break;
    }
   }
  }
 }
 printf("%d",ans);
 return 0;
}

#10002. 「一本通 1.1 例 3」喷水装置

题目

题目大意

长L米,宽W米的草坪里装有n个浇灌喷头。

每个喷头都装在草坪中心线上。

知道每个喷头的位置,以及它能覆盖到的浇灌范围。

问同时浇灌整块草坪最少需要打开多少个喷头?

对于100%的数据,n<=15000。

题目分析

. . “.” . .

. “.” .

“.”

. “.” .

. . “.” . .

下划线的为半径,“引号”中的是草坪宽。

红色的是能浇灌到的最边上的草坪宽,用kk=sqrt(r*r-(w/2)*(w/2))表示。是美妙的勾股啊!!

则最左边a[s].a=x-kk,最右边a[s].b=x+kk。

如果浇灌的半径*2<草坪宽就不考虑这个喷头,不要问我为什么,或者你告诉我要它有何用。

剩下的水到渠成。

还不懂就看代码吧。

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

struct node{double a,b;}a[15010];
int cmp(node x,node y) { return x.a<y.a; }

int main()
{
 int t; scanf("%d",&t);
 while(t--)
 {
  int n,l,w,s=0; scanf("%d%d%d",&n,&l,&w);
  for(int i=1;i<=n;i++)
  {
   int x,y; scanf("%d%d",&x,&y);
   if(y*2<w) continue; s++;
   double kk=sqrt(y*y*1.0-w*w/4.0);
   a[s].a=x*1.0-kk;//能浇灌到的最边上的最左
   a[s].b=x*1.0+kk;//能浇灌到的最边上的最右
  }
  sort(a+1,a+1+s,cmp);
  int d=1,ans=0;
  double ll=0;//目前能浇灌到的最边上的草坪的长  
  bool k=true;
  while(ll<l)//革命尚未成功 
  {
   ans++; double maxx=ll;
   while(a[d].a<=maxx&&d<=s)
   {
    ll=max(ll,a[d].b); d++;
    //当然是找符合要求且半径长的喷头a 
   }
   if(maxx==ll) { printf("-1\n"); k=false; break; }
  }
  if(k) printf("%d\n",ans);
 }
 return 0;
}

#10003. 「一本通 1.1 例 4」加工生产调度

题目

题目大意

n个产品在A、B两个车间加工,必须先在A车间加工后才可以到B车间加工。

产品i在A,B两车间加工的时间分别为 A_i, B_i,安排这 n个产品的加工顺序,使总的加工时间最短。

对于100%的数据,0<n<1000,所有数值皆为整数。

题目分析

???没有分析,很迷???

一本通上的证明并没有看懂,我太辣鸡了。

反正是这样做的:

设Mi=min(ai,bi)。

将M从小到大排序,若Mi=ai,就将它放在从头开始的作业后面。

反之放在从尾开始的作业前面。

顺序排好了就直接做啊。

代码

#include<cstdio>
#include<cstring>
#include<cstring>
#include<algorithm>
using namespace std;

int s[1010];
struct nod1{int a,b,m,h;}a[1010];
struct nod2{int a,b;}b[1010];
int cmp(nod1 x,nod1 y) { return x.m<y.m; }

int main()
{
 int n; scanf("%d",&n);
 for(int i=1;i<=n;i++) scanf("%d",&a[i].a);
 for(int i=1;i<=n;i++)
 {
  scanf("%d",&a[i].b);
  a[i].m=min(a[i].a,a[i].b); a[i].h=i;
  b[i].a=a[i].a; b[i].b=a[i].b;
 }
 sort(a+1,a+1+n,cmp);
 int st=1,ed=n;
 for(int i=1;i<=n;i++)
 {
  if(a[i].m==a[i].a) { s[st]=a[i].h; st++; }
  else { s[ed]=a[i].h; ed--; }
 }
 int ans=0,d=0;
 for(int i=1;i<=n;i++)
 {
  d+=b[s[i]].a;
  ans=max(d+b[s[i]].b,ans+b[s[i]].b);
 }
 printf("%d\n",ans);
 for(int i=1;i<=n;i++) printf("%d ",s[i]);
 return 0;
}

#10004. 「一本通 1.1 例 5」智力大冲浪

题目

题目大意

比赛分为n个时段,每个游戏都必须在t_i前完成,否则从奖励费m元中扣去一部分钱 w_i。

每个游戏能在一个时段内完成,问小伟能赢取最多的钱。

对于100%的数据,有n<=500,1<=t_i<=n。

题目分析

肯定挑钱多的先做啊,需要为什么吗???

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

bool f[250010];
struct node{int time,money;}a[510];
int cmp(node x,node y) { return x.money>y.money; }

int main()
{
 int m,n; scanf("%d%d",&m,&n);
 memset(f,false,sizeof(f));
 for(int i=1;i<=n;i++) scanf("%d",&a[i].time);
 for(int i=1;i<=n;i++) scanf("%d",&a[i].money);
 sort(a+1,a+1+n,cmp);//按钱的多少排序
 for(int i=1;i<=n;i++)
 {
  bool k=false;
  for(int j=a[i].time;j>=1;j--)
  {
   if(!f[j]) { f[j]=true; k=true; }
   if(k) break;
  }
  if(!k) m-=a[i].money;
 }
 printf("%d",m);
 return 0;
}

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP