【贪心】

*本人2018级大一,软件工程在读,实力水,本文是为了让我记笔记而诞生。
如果很闲 有兴趣的新手欢迎一起进步。
笔记始于2018.11.18
目前持续更新,待完结。
手动目录:合并果子
数列分段
纪念品分组
交作业扣分少
泥坑铺木板
写论文得奖学金
Moving Tables
Stall Reservations //奶牛矫情的挤奶时间安排
Packets//打包

[p1090] 合并果子

[题目]https://www.luogu.org/problemnew/show/P1090
思路:刚开始天真的看错题目,以为只是排序后,前两者相加的值加上第三个的值,以此类推,感觉是有种递归的含义,然后写完了发现样例是可以过,就傻傻的提交了,然后…QAQ
一脸懵逼
错误代码就不贴了,后来发现了问题所在:**每次都要最小的两个果堆相加才行!**然后想每次都sort排序就好了呀!然后…就超时了.
最后走投无路的我点开了题解,围观了dalao的代码。
使用了可能是动态规划/递归?的思路~~(目前我也不太清楚)~~ 。
所以这其实别人的思路,但是理解学习了。(菜鸡阶段尽量学习)

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

int main()
{
    int n,sum=0;//sum为消耗的总体力值
    int a[10002]= {0};//菜鸡的数组输入(可以队列代替)
    while(scanf("%d",&n)!=EOF)//多组输入
    {
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
        }
        int t;//中间值
        sort(a+1,a+n+1);//排序  /*从小到大*/
        while(1)
        {
            int j=1;
            if(n==1)
                break;//当n只有一个堆时,结束循环
            else
            {
                a[j]+=a[j+1];//第一堆果子等于本身加下一堆果子
                sum+=a[j];//计算总值
                for(int i=j+1; i<n; i++)
                {
                    a[i]=a[i+1];//因为第二堆果子已经去了第一堆,
                    //将第三堆至最后一堆整体前移
                }
                n--;
                for(int i=1; i<n; i++)
                {
                    if(a[i]>a[i+1])
                    {
                        swap(a[i],a[i+1]);//交换,使刚刚新得到的堆在正确位置
                    }
                }
            }

        }
        printf("%d\n",sum);

    }

}

我觉得这种做法还挺容易理解的,此题还有优先队列的做法,这里附上<古暗杀者>的代码,我觉得特别巧妙,如有侵犯,联系删除。//写了搜索后发现原来队列应用还挺广泛,只是我无知(18.12.6

#include<bits/stdc++.h>
using namespace std;
int n,b,j;
priority_queue<int>s; //定义队列
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>b;
        s.push(-b);//*-1后再压入队列,这样的话现在最小值就是原来的最大值
    }
    for(int i=1;i<n;i++)//循环n-1次
    {
        b=s.top();//弹出最小值(此最小值为原来的最小值,后文同样如此)
        s.pop();//删除最小值
        b+=s.top();//弹出第二小值
        s.pop();//删除第二小值
        s.push(b);//重新压入队列
        j+=b;//计数
    }
    cout<<j*-1;//输出-1*计数器
    return 0;//结束代码
 }

[p1181]数列分段

[题目]https://www.luogu.org/problemnew/show/P1181

思路:写完这题,我发现贪心算法的一件事:最好不要在循环的某一次试图判断然后改变下一次的值(下场惨烈),可以考虑定义另一个数temp(初始化),每次循环判断前,利用temp(上次循环得到的需要改变的值)改变这一次的值。(语死早)
此题并不难,但是我由于前面说的傻事WA了n次.

依照旧例,先放错误代码//我也不知道哪里错了…有人看出来拜托告诉我

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
int a[100010];
using namespace std;
int main()
{
    int n,m,sum=0;
    cin>>n>>m;
    memset(a,0,n+1);
    for(int i=0; i<n; i++)
    {
        scanf("%d",&a[i]);
    }
    for(int i=0; i<n; i++)
    {
        int b;
        if(i<n-1)
        {
            if(a[i]>=m)
            {
                sum+=a[i]/m;
                a[i+1]+=a[i]%m;
            }
            else
            {
                  a[i+1]+=a[i];

            }
        }

        else if(i==n-1)
        {
              if(a[i]>=m)
              {
                    if(a[i]%m==0)
                    {
                          sum+=a[i]/m-1;
                    }
                    else
                    {
                          sum=sum+a[i]/m+1;
                    }

              }
              else
              {
                    sum+=1;
              }
        }

    }
    printf("%d\n",sum);

}



正确代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
int a[100010];
using namespace std;
int main()
{
    int n,m,sum=0,yu=0;
    cin>>n>>m;
    memset(a,0,n+1);
    for(int i=0; i<n; i++)
    {
        scanf("%d",&a[i]);
    }
    for(int i=0; i<n; i++)
    {
          if(a[i]+yu>m)
          {
                yu=0;
                sum++;

          }
          yu=yu+a[i];

    }
    if(yu)
    {
          sum++;
    }


    printf("%d\n",sum);

}

[p1094]纪念品分组

[题目]https://www.luogu.org/problemnew/show/P1094

思路:先从小到大排序,因为一组最多两件,贪心思想,如果最小的加最大的符合,那就是很划算了。(别问为啥,数学直觉(手动狗头)),如果这两个不符合,那说明最大的那个只能单独一组了,那么max往前走一个,最大值改变。不算难的想法。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int a[30002];
int main()
{
    int w,n,sum=0,x,y;
    while(scanf("%d %d",&w,&n)!=EOF)
    {
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
        }
        sort(a+1,a+1+n);
        x=1;
        y=n;
        while(x<=y)
        {
            if(a[x]+a[y]<=w)
            {
                sum++;
                x++;
                y--;
            }
            else
            {
                sum++;
                y--;
            }
        }
        printf("%d\n",sum);
    }


}

[贪心思想]交作业使扣分最少

题目:Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lot of homework to do. Every teacher gives him a deadline of handing in the homework. If Ignatius hands in the homework after the deadline, the teacher will reduce his score of the final test. And now we assume that doing everyone homework always takes one day. So Ignatius wants you to help him to arrange the order of doing homework to minimize the reduced score.
Input
The input contains several test cases. The first line of the input is a single integer T that is the number of test cases. T test cases follow.
Each test case start with a positive integer N(1<=N<=1000) which indicate the number of homework… Then 2 lines follow. The first line contains N integers that indicate the deadlines of the subjects, and the next line contains N integers that indicate the reduced scores.
Output
For each test case, you should output the smallest total reduced score, one line per test case.
Sample Input
3
3
3 3 3
10 5 1
3
1 3 1
6 2 3
7
1 4 6 4 2 4 3
3 2 1 7 6 5 4
Sample Output
0
3
5

思路:我们肯定要找性比价高的开始,尽量从最后一天开始,两门作业如果分数不同,那么分数高的在前面先完成,如果分数相同,我们优先写晚提交的作业。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
int flag[1004];
using namespace std;

struct inp//结构体
{
    int t,f;//时间t,分数f
}node[1004];

int cmp(inp a,inp b)//比较方法
{
      if(a.f!=b.f)
            return a.f>b.f;
      else
            return a.t>b.t;
}
int main()
{
      int t,n,maxi,m,sum;
      while(scanf("%d",&t)!=EOF)//标准多组输入
      {
            while(t--)//t组测试用例
            {
                  memset(flag,0,sizeof(flag));
                  cin>>n;//课程数量
                  maxi=0;
                  m=0;
                  for(int i=0;i<n;i++)
                  {
                        cin>>node[i].t;
                        if(node[i].t>maxi)
                        {
                              maxi=node[i].t;//比较并记录最后的提交期限
                        }
                  }
                  for(int i=0;i<n;i++)
                  {
                        cin>>node[i].f;
                        m+=node[i].f;//m为所有扣分总值
                        if(node[i].t>maxi)
                        {
                              maxi=node[i].t;

                        }
                  }
                  sort(node,node+n,cmp);//按分数从高到低排
                                        //如果分数相同,按天数从远到进

                  for(int i=0;i<n;i++)
                  {
                        for(int j=node[i].t;j>0;j--)//j为这门功课提交期限天数
                        {
                              if(flag[j]==0)//如果这门功课上交期限前能完成则
                              {             //flag为这门功课的分数
                                    flag[j]=node[i].f;//i是按分数最大先排序
                                    break;//跳出,这天天数flag不为0

                              }

                        }
                  }
                  sum=0;
                  for(int i=0;i<=maxi;i++)
                  {
                        sum+=flag[i];
                  } 
                  printf("%d\n",m-sum);

            }
            
      }
      return 0;
}

[贪心思想] 泥坑铺木板的最少木板数

Farmer John has a problem: the dirt road from his farm to town has suffered in the recent rainstorms and now contains (1 <= N <= 10,000) mud pools.
Farmer John has a collection of wooden planks of length L that he can use to bridge these mud pools. He can overlap planks and the ends do not need to be anchored on the ground. However, he must cover each pool completely.
Given the mud pools, help FJ figure out the minimum number of planks he needs in order to completely cover all the mud pools.
Input
Line 1: Two space-separated integers: N and L
Lines 2…N+1: Line i+1 contains two space-separated integers: s_i and e_i (0 <= s_i < e_i <= 1,000,000,000) that specify the start and end points of a mud pool along the road. The mud pools will not overlap. These numbers specify points, so a mud pool from 35 to 39 can be covered by a single board of length 4. Mud pools at (3,6) and (6,9) are not considered to overlap.
Output
Line 1: The miminum number of planks FJ needs to use.
Sample Input
3 3
1 6
13 17
8 12
Sample Output
5

思路:按顺序排序,从最左边开始铺路,如果木板此时长度大于此处泥坑的右边,那么此处不用铺木板。

#include <cstring>
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
struct ni
{
    int  a,b;//a是泥坑左边,b是泥坑右边
} nn[10010];
int cmp(struct ni m,struct ni n)
{
    return m.a<n.a;//排序
}
int main()
{
    int n,l,sum=0,muban=0;
    scanf("%d %d",&n,&l);//偷懒了没用多组输入
    for(int i=1; i<=n; i++)
    {
        scanf("%d %d",&nn[i].a,&nn[i].b);
    }
    sort(nn+1,nn+1+n,cmp);
    muban=0;//木板此时在0处
    for(int i=1; i<=n; i++)
    {
        if(muban>=nn[i].b)
        {
            continue;
        }
        muban=max(nn[i].a,muban); //木板等于两者最大的那个
                                 //感谢c++拥有max()函数
        while(muban<nn[i].b)//直到木板铺到此处泥坑右边才结束
        {
            sum++;
            muban+=l;
        }
    }
    printf("%d\n",sum);

}

Vanya and Exams
Vanya wants to pass n exams and get the academic scholarship. He will get the scholarship if the average grade mark for all the exams is at least avg. The exam grade cannot exceed r. Vanya has passed the exams and got grade ai for the i-th exam. To increase the grade for the i-th exam by 1 point, Vanya must write bi essays. He can raise the exam grade multiple times.
What is the minimum number of essays that Vanya needs to write to get
scholarship?

Input
The first line contains three integers n, r, avg (1 ≤ n ≤ 105,1 ≤ r ≤ 109, 1 ≤ avg ≤ min(r, 106)) — the number of exams, the maximum grade and the required grade point average, respectively.
Each of the following n lines contains space-separated integers ai and bi (1 ≤ ai ≤ r, 1 ≤ bi ≤ 106).

Output
In the first line print the minimum number of essays.

Examples
Input
5 5 4 5 2 4 7 3 1 3 2 2 5
Output
4

Input 2 5 4 5 2 5 2
Output
0

Note In the first sample Vanya can write 2 essays for the 3rd exam to raise his grade by 2 points and 2 essays for the 4th exam to raise his grade by 1 point.

In the second sample, Vanya doesn’t need to write any essays as his general point average already is above average.

[思路]:其实刚开始又又又又看错题目了(捂脸),本题的意思是妹子想要奖学金,得到奖学金的条件是总分sum要不小于平均成绩avg*科目总数n,妹子每写bi篇论文,i科分数就+1,同时分数不能超过r,问你妹子最少要写多少篇论文。我们排序当然要按bi小的在前面的方式排了,划算懂吗?//ai还得满足大于avg

#include<stdio.h>
#include <iostream>
#include <algorithm>
using namespace std;
long long n,r,avg,sumavg,sum,ans;
struct node
{
    int a,b;
} N[100005];
int cmp(struct node x,struct node y)
{
      return x.b<y.b;
}
int main()
{
    while(scanf("%d %d %d",&n,&r,&avg)!=EOF)
    {
        sumavg=avg*n;//平均总分
        sum=0;//总分
        for(int i=1; i<=n; i++)
        {
            scanf("%d %d",&N[i].a,&N[i].b);
            sum+=N[i].a;//相加和
        }
        if(sum>=sumavg)//已经满足则输出,否则继续
        {
              printf("0\n");
              continue;
        }
        ans=0;
        sort(N+1,N+n+1,cmp);//排序
        for(int i=1; i<=n; i++)
        {
           long long t=min(sumavg-sum,r-N[i].a);//理解一下,其实挺容易的
           sum+=t;//相加
           ans+=t*N[i].b;//计算

        }
        printf("%I64d\n",ans);//输出
    }
    return 0;
}

Moving Tables
The famous ACM (Advanced Computer Maker) Company has rented a floor of a building whose shape is in the following figure.

The floor has 200 rooms each on the north side and south side along the corridor. Recently the Company made a plan to reform its system.The reform includes moving a lot of tables between rooms. Because the
corridor is narrow and all the tables are big, only one table can pass through the corridor. Some plan is needed to make the moving efficient. The manager figured out the following plan: Moving a table from a room to another room can be done within 10 minutes. When moving a table from room i to room j, the part of the corridor between the front of room i and the front of room j is used. So, during each 10 minutes, several moving between two rooms not sharing the same part of the corridor will be done simultaneously. To make it clear the manager illustrated the possible cases and impossible cases of simultaneous moving.

For each room, at most one table will be either moved in or moved out.
Now, the manager seeks out a method to minimize the time to move all the tables. Your job is to write a program to solve the manager’s problem.

Input
The input consists of T test cases. The number of test cases ) (T is given in the first line of the input. Each test case begins with a line containing an integer N , 1<=N<=200 , that represents the number of tables to move. Each of the following N lines contains two positive integers s and t, representing that a table is
to move from room number s to room number t (each room number appears at most once in the N lines). From the N+3-rd line, the remaining test > cases are listed in the same manner as above.
Output
The output should contain the minimum time in minutes to complete the moving, one per line. Sample

Input
3
4
10 20
30 40
50 60
70 80
2
1 3
2 200
3
10 100
20 80
30 50

Sample Output
10
20
30

[思路]:怎么说,开始没想到怎么做,因为标记这段路目前被人使用是比较麻烦的事情,然后通过别人的题解,我发现搬桌子没有时间限制//不知道怎么表述,下一题就是反例,因此学会了用数组计数表示。

#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
int rooms[201]= {0};
int main()
{
    int T,N,s,e,sum;
    scanf("%d",&T);
    while(T--)
    {
        sum=0;
        memset(rooms,0,sizeof(rooms));
        scanf("%d",&N);
        for(int i=0; i<N; i++)
        {
            scanf("%d %d",&s,&e);
            if(s>e)
            {
                swap(s,e);
            }
            for(int k=(s+1)/2; k<=(e+1)/2; k++)
            {
                rooms[k]++;
            }

        }
        for(int i=0; i<201; i++)
        {
            sum=max(sum,rooms[i]);//最大的计数
        }

        printf("%d\n",sum*10);
    }
}

Stall Reservations
Oh those picky N (1 <= N <= 50,000) cows! They are so picky that each one will only be milked over some precise time interval A…B (1 <= A <= B <= 1,000,000), which includes both times A and B. Obviously, FJ must create a reservation system to determine which stall each cow can be assigned for her milking time. Of course, no cow will share such a private moment with other cows.

Help FJ by determining: The minimum number of stalls required in the barn so that each cow can have her private milking period An assignment of cows to these stalls over time Many answers are correct for each test dataset; a program will grade your answer.
Input Line 1: A single integer, N
Lines 2…N+1: Line i+1 describes cow i’s milking interval with two space-separated integers.
Output Line 1: The minimum number of stalls the barn must have.
Lines 2…N+1: Line i+1 describes the stall to which cow i will be assigned for her milking period. Sample

Input
5
1 10
2 4
3 6
5 8
4 7
Sample Output
4
1
2
3
2
4

Hint Explanation of the sample
Here’s a graphical schedule for this output:

Time 1 2 3 4 5 6 7 8 9 10

Stall 1 c1>>>>>>>>>>>>>>>>>>>>>>>>>>>

Stall 2 … c2>>>>>> c4>>>>>>>>> … …

Stall 3 … … c3>>>>>>>>> … … … …

Stall 4 … … … c5>>>>>>>>> … … … Other outputs using the same number of stalls are possible.

[思路]:emmm对我而言并不好写,毕竟我还不会重载运算符,这题目意思很简单,思路也很容易,但是转换成代码对于2018.12.7的我而言不算容易。[突然知道这个好像和cmp差不多//

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
struct cow
{
    int bg,ed,num;
    bool friend operator <(cow a,cow b)
    {
        return a.ed>b.ed;
    }
} x[100005];

bool cmp(cow a,cow b)
{
    if(a.bg==b.bg)
    {
        a.ed<b.ed;//最早结束的
    }
    return a.bg<b.bg;
}
int main()
{
    int n,num[50005];
    while(~scanf("%d",&n))
    {
        priority_queue<cow> q;//默认用bool friend operator <(cow a,cow b)的优先级
        for(int i=0; i<n; ++i)
        {
            scanf("%d%d",&x[i].bg,&x[i].ed);
            x[i].num=i;//牛编上号
        }
        sort(x,x+n,cmp);//排序
        int cnt=0;
        num[x[0].num]=cnt++;//第一头牛的编号
        q.push(x[0]);
        for(int i=1; i<n; ++i)
        {
            cow st=q.top();
            if(x[i].bg>st.ed)//有头牛的时间结束
            {
                q.pop();
                num[x[i].num]=num[st.num];//下头牛 使用这个编号
            }
            else//当前没有结束
            {
                num[x[i].num]=cnt++;
            }
            q.push(x[i]);
        }
        printf("%d\n",cnt);
        for(int i=0; i<n; ++i)
        {
            printf("%d\n",num[i]+1);
        }
    }
    return 0;
}

A factory produces products packed in square packets of the same height h and of the sizes 11, 22, 33, 44, 55, 66. These products are always delivered to customers in the square parcels of the same height h as the products have and of the size 66. Because of the expenses it is the interest of the factory as well as of the customer to minimize the number of parcels necessary to deliver the ordered products from the factory to the customer. A good program solving the problem of finding the minimal number of parcels necessary to deliver the given products according to an order would save a lot of money. You are asked to make such a program.
Input
The input file consists of several lines specifying orders. Each line specifies one order. Orders are described by six integers separated by one space representing successively the number of packets of individual size from the smallest size 1
1 to the biggest size 6*6. The end of the input file is indicated by the line containing six zeros.
Output
The output file contains one line for each line in the input file. This line contains the minimal number of parcels into which the order from the corresponding line of the input file can be packed. There is no line in the output file corresponding to the last ``null’’ line of the input file.
Sample Input
0 0 4 0 0 1
7 5 1 0 0 0
0 0 0 0 0 0
Sample Output
2
1

[思路]:将体积转换看待成面积,贪心思想就是先将最大的66放好,然后因为55,44,66必定每个都要占一个包装,哪怕会有剩余空间,那个剩余空间我们先用22的试图填满,然后再考虑11。

#include<stdio.h>
#include <iostream>
#include <math.h>
#include <algorithm>
using namespace std;
int sum;
int a,b,c,d,e,f;
int tab[]= {0,5,3,1}; //tab[i]表示放i个3*3的,还能放多少2*2的
int main()
{
    while(scanf("%d %d %d %d %d %d",&a,&b,&c,&d,&e,&f)!=EOF)
    {
        if(!a&&!b&&!c&&!d&&!e&&!f)
            break;
        sum=0;
        int num3=ceil(c*1.0/4.0);//3*3的有4个刚好填满6*6
        sum+=d+e+f+num3;//4*4,5*5,6*6分别必定各占一个箱子
        int num2=5*d+tab[c%4];//统计能放2*2的个数 //放入4*4大小的箱子还可以再放5个2*2
        num2=min(num2,b);//较小的,因为可能不够
        b-=num2;//剩下的2*2
        int rest=36*sum-f*36-e*25-d*16-c*9-num2*4;//放入4*4,5*5,6*6的箱子中剩下的空间
        rest=min(rest,a);
        a-=rest;
        rest=b*4+a;
        sum+=ceil(rest/36.0);
        printf("%d\n",sum);

    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值