2021-03-27

贪心思路总结

发现贪心算法重在思路,如果思路清晰,知道了贪心的标准,然后按照这个标准来写码,再留意细节 基本上简单题都能ac;
下面是整理的一些题目

看电视问题(区间调度)

例题1
(目标是能看尽量多的完整节目)
思路: 题目意思是说 一天时间 从0~24小时 这一个线性区间;中间有几个小区间来代表节目的播放时间 如果区间有重叠的部分 就只能选则一个;从0到24小时最多能有几个不重叠的区间;
我们先按照节目的结束时间排序升序;只要结束时间早 ,我后面的选择就多

 sort(jm,jm+n,cmp);
           int sum=0;
           int a=0;
           for(int i=0;i<n;i++)
            if(a<=jm[i].s)
            {
            a=jm[i].j;
           sum++;
            }
            cout<<sum<<endl;

先给结束时间排序 从第一个节目开会遍历如果该节目的结束时间小于等于下一个节目开始时间 就把下一个节目选上 然后把结束时间变成下一个节目结束的时间;
变例
选课问题
意思是 题目大意:一共有N门课可以选,但选课时每次必须间隔5分钟。例如你在5分07秒选了一门课,那必须在10分07秒选下一门课.。每一门课的的选课是有时间限制的,你只能在Ai到Bi之间选中第i门课。求你能选择的课最多多少门
先输入N,表示一共有N门课。
接下来N行,每行两个整数,为课程可以被选择中的时间段。开始时间和结束时间
思路:如果不看每隔五分钟这个条件的话 这个题和上一个题没两样;
加上这五分钟必须选择一次课的限定条件 我们可以枚举 0,1,2,3,4分钟 ;即分六种情况来讨论 开始时间是 0,1,2,3,4分钟 (因为第5分钟开始选和第0分钟开始选择可选择的课一样)然后就是区间调度问题了

bool cmp(Node A,Node B){
    if(A.r!=B.r)return A.r<B.r;
    return A.l<B.l;



int true_ans=0;
        for(int start=0;start<5;start++){//枚举5个选课时刻
            for(int i=0;i<N;i++)vis[i]=false;//vis用来记录是否被选上
             int ans=0;
            for(int i=start;i<1001;i+=5){枚举每个选课时刻对应的所有选课时间
                for(int j=0;j<N;j++){
                    if(vis[j])continue;
                    if(i>=node[j].l&i<node[j].r){
                        vis[j]=true;
                        ans++;
                        break;
                    }
                }
            }
            true_ans=max(true_ans,ans);//比较每种情况的大小;要大的
            

变例2
搬桌子问题
意思是 一个线性排列的房间 1到n 现要求你从m房间搬到n房间 但是在搬运过程中 m到n的走廊被占用 其他地段的走廊可以正常搬运;搬运一次无论远近要10分钟 问搬运需要的最少时间;
思路就是 m到n是一个区间,每个区间看成是几个房子连接起来的 所有区间的房子重叠最大个数*10就是答案

for(int i=0;i<n;i++)

     {
             if(a[i].s>a[i].e)
         {
               ans=a[i].e;
         a[i].e=a[i].s;
         a[i].s=ans;
         }//保证区间是正区间

          for(int j=a[i].s;j<=a[i].e;j++)//m到n 的每个房子都自增
           flag[j]++;

      }
      for(int i=0;i<=400;i++)
           sum=sum>flag[i]?sum:flag[i];//sum=最大的房子重叠数量
           cout<<sum*10;

损失问题

做作业问题
有n个作业 每个作业都有截止日期和超过日期的罚分 并且一天只能做一个
问怎样安排罚分最少;
思路:
1 课上讲过得 先按照结束时间升序 时间相同按照罚分降序;先把最先截止的作业做了 ,如果某天有一个作业超时了 就用该作业的罚分和前面要做的作业罚分比较 去除选择罚分最少的不做,依次类推;
2 排序学分降序 作业1截止当天要是没有时间冲突就做它,该天做上标记 下次遇到该天就跳过,要是作业2截止当天有冲突就往前面的天推 遇到没有作业的那天就做 记录下来总的学分和被选择的作业的总学分;两者的差就是罚分最少

 memset(flag,false,sizeof(flag));//用来标记的数组
     for(int i=0;i<n;i++)
      cin>>a[i].e;
      for(int i=0;i<n;i++)
      {cin>>a[i].xf;
      ans+=a[i].xf;//总学分
      }

      sort(a,a+n,cmp);//大学分在前
      for(int j=0;j<n;j++)
      {  int day=a[j].e;//从截止当天开始向前遍历
        for(day;day>0;day--)
            if(!flag[day])
            {sum+=a[j].xf;//学分大的作业的总学分
             flag[day]=true;
                  break;
            }

       }
cout<<ans-sum;

这一个做作业问题和 销售东西问题一模一样
销售东西问题 有n个物品要出售 有价格和销售截止时间 一天只能买怕卖一件
问最大的销售额是多少
思路和上面的做作业思路一样
先按照价格排序 从截止当天往前遍历 如果当天没买东西就出售 然后标记 ;下一件商品 以此类推 所有被标记的商品就是所出售的;价格和就是答案;

数学类问题

这类问题主要是靠分析案例然后列出来函数代数或者是不等式 推出来的贪心标准;
例如
物体碰撞质量损失问题,牛吃花的问题,牛交流的问题;
碰撞问题:
给出n 个物体,分别给出每个的质量,并且两个物体(假设质量分别为m1,m2)相撞的时候变成一个物体,质量为2sqrt(m1m2),并且只会出现两个两个物品碰撞的情况,问最终能得到的物体的最小质量是多少。
思路:
设质量为a, b, c,令a > b > c >,则有:
Ans = sqrt(sqrt(2 * a * b) * c * 2) or
Ans = sqrt(2 * a * sqrt(2 * b * c))
可见在一式中最大数a被两次开根,而二式中只一次开根,那么一式要比二式更优,于是每次选择最大的两个数开根计算,让大数尽量多被开根答案最小.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值