• 贪心


    1422:【例题1】活动安排

    将终点进行一个排序之后来进行贪心的计算

    【题目描述】
    设有nn个活动的集合E={1,2,…,n}E={1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。每个活动ii都有一个要求使用该资源的起始时间sisi和一个结束时间fifi,且si<fisi<fi。如果选择了活动ii,则它在半开时间区间[si,fi)[si,fi)内占用资源。若区间[si,fi)[si,fi)与区间[sj,fj)[sj,fj)不相交,则称活动ii与活动jj是相容的。也就是说,当si≥fjsi≥fj或sj≥fisj≥fi时,活动ii与活动jj相容。选择出由相互兼容的活动组成的最大集合。
    
    【输入】
    第11行一个整数n(n≤1000)n(n≤1000),接下来nn行,每行两个整数sisi和fifi。
    
    【输出】
    输出尽可能多的互相兼容的活动个数。
    
    【输入样例】
    4
    1 3
    4 6
    2 5
    1 7
    【输出样例】
    2
    1422:【例题1】活动安排
    #include <bits/stdc++.h>
    using namespace std;
    const int N=1005;
    struct h{
        int en;
        int be;
    }a[1005];
    bool cmp(h a,h b)
    {
        return a.en<b.en;
    }
    int main()
    {
        int n;
        int sum=0;
        int endd=-1;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i].be>>a[i].en;
        }
        sort(a+1,a+n+1,cmp);
        for(int i=1;i<=n;i++)
        {
            if(a[i].be>=endd)
            {
                sum++;
                endd=a[i].en;
            }
        }
        cout<<sum<<endl;
        return 0;
    }
    View Code

    1423:【例题2】种树

    同样也是将每一个区域的重点进行一个排序,先是从前往后看前面是否有重合的已经种了树的,如果该区域还没有达到要求的话,就从后面开始种树,因为尾部是最容易有重合的地方

    【题目描述】
    现在我们国家开展新农村建设,农村的住房建设纳入了统一规划,统一建设,政府要求每一住户门口种些树。门口路边的地区被分割成块,并被编号成1..N。每个部分为一个单位尺寸大小并最多可种一棵树。每个居民房子门前被指定了三个号码B,E,T。这三个数表示该居民想在B和E之间最少种T棵树。当然,B≤E,居民必须记住在指定区不能种多于区域地块数的树,所以T≤E-B+l。居民们想种树的各自区域可以交叉。你的任务是求出能满足所有要求的最少的树的数量,尽量较少政府的支出。
    
    【输入】
    第一行包含数据N,M,区域的个数(0<N≤30000),房子的数目(0<m≤5000);
    
    下面的m行描述居民们的需要:B E T,0<B≤E≤30000,T≤E-B+1。
    
    【输出】
    输出一个数,为满足所有居民的要求,所需要种树的最少数量。
    
    【输入样例】
    9 4
    3 5 2
    1 4 2
    4 6 2
    8 9 2
    【输出样例】
    5
    种树
    #include <bits/stdc++.h>
    using namespace std;
    const int N=30005,M=5005,inf=0x3f3f3f;
    struct line{
        int s,e,num;
    }a[N];
    int vis[N]; 
    bool cmp(line x,line y){
        return x.e<y.e;
    }
    int main()
    {
        int n,m,ans=0,k;
        cin>>n>>m;
        for(int i=1;i<=m;i++) cin>>a[i].s>>a[i].e>>a[i].num;
        sort(a+1,a+1+m,cmp);
        for(int i=1;i<=m;i++){
            k=0;
            for(int j=a[i].s;j<=a[i].e;j++)
                if(vis[j]) k++;//记录已经种了树的区域
            if(k>=a[i].num) continue;//已经满足此区域的要求
            for(int j=a[i].e;j>=a[i].s;j--){//从尾巴是最有可能和下一个区域重合的 
                if(!vis[j]){
                vis[j]=1;k++;ans++;    
                if(k==a[i].num) break;
                }    
            } 
        }
        cout<<ans;
        return 0;
    }
    View Code

    1424:【例题3】喷水装置

    【题目描述】
    长 LL 米,宽 WW 米的草坪里装有 nn 个浇灌喷头。每个喷头都装在草坪中心线上(离两边各 W2W2 米)。我们知道每个喷头的位置(离草坪中心线左端的距离),以及它能覆盖到的浇灌范围。
    
    
    
    请问:如果要同时浇灌整块草坪,最少需要打开多少个喷头?
    
    【输入】
    输入包含若干组测试数据。
    
    第一行一个整数 TT 表示数据组数;
    
    每组数据的第一行是整数 nn、LL 和 WW;
    
    接下来的 nn 行,每行包含两个整数,给出一个喷头的位置和浇灌半径(上面的示意图是样例输入第一组数据所描述的情况)。
    
    【输出】
    对每组测试数据输出一个数字,表示要浇灌整块草坪所需喷头数目的最小值。如果所有喷头都打开也不能浇灌整块草坪,则输出 −11 。
    
    【输入样例】
    3
    8 20 2
    5 3
    4 1
    1 2
    7 2
    10 2
    13 3
    16 2
    19 4
    3 10 1
    3 5
    9 3
    6 1
    3 10 1
    5 3
    1 1
    9 1
    【输出样例】
    6
    2
    -1
    【提示】
    数据范围:
    
    对于 100% 的数据,n≤15000
    喷水装置

     其实有用到勾股定理,自己画图理解下,然后按照起点从小到大排序,先找在起点在草坪左端的,谁的右边最大,依次这样下去;如果没有就在草坪右边的就不行,最后求出的右端点小于草坪的长度也是不行

    #include <bits/stdc++.h>
    using namespace std;
    const int N=20005,inf=0x3f3f3f;
    struct line{
        double s,e;
    }a[N]; 
    int n,l,w,x,r,cnt;
    bool cmp(line x,line y)
    {
        return x.s<y.s;
    }
    void init()
    {
        cnt=0;
        cin>>n>>l>>w;
        for(int i=1;i<=n;i++)
        {
            cin>>x>>r;
            if(r<=w/2) continue;
            cnt++;
            a[cnt].s=x-sqrt(r*r-w*w/4.0);
            a[cnt].e=x+sqrt(r*r-w*w/4.0);
        }
    }
    void solve()
    {
        double t=0;
        int ans=0,bj=1,i=1;
        while(t<l){
            ans++;
            double s=t;
            for(;a[i].s<=s&&i<=cnt;i++)//找到能够覆盖左端点的最靠近右边的点 
                if(t<a[i].e) t=a[i].e;
            if(t==s&&s<l){
                cout<<-1<<endl;
                bj=0;break;
            } 
        }
        if(bj) cout<<ans<<endl;
    }
    int main()
    {
        int t;cin>>t;
        while(t--){
            init();
            sort(a+1,a+1+cnt,cmp);
            solve();
        }
        return 0;
    }
    View Code

    1425:【例题4】加工生产调度

    【题目描述】
    某工厂收到了 nn 个产品的订单,这 nn 个产品分别在 A、B 两个车间加工,并且必须先在 A 车间加工后才可以到 B 车间加工。
    
    某个产品 ii 在 A,B 两车间加工的时间分别为Ai,BiAi,Bi。怎样安排这 nn 个产品的加工顺序,才能使总的加工时间最短。
    
    这里所说的加工时间是指:从开始加工第一个产品到最后所有的产品都已在 A,B 两车间加工完毕的时间。
    
    【输入】
    第一行仅—个数据 nn ,表示产品的数量;
    
    接下来 nn 个数据是表示这 nn 个产品在 A 车间加工各自所要的时间;
    
    最后的 nn 个数据是表示这 nn 个产品在 B 车间加工各自所要的时间。
    
    【输出】
    第一行一个数据,表示最少的加工时间;
    
    第二行是一种最小加工时间的加工顺序。
    
    【输入样例】
    5
    3 5 8 7 10
    6 2 1 4 9
    【输出样例】
    34
    1 5 4 2 3
    【提示】
    对于100%的数据, 0 < n < 10000,所有数值皆为整数。
    1425:【例题4】加工生产调度

    Johnson算法:设N1为a<b的作业集合,N2为a>=b的作业集合,将N1的作业按a非降序排序,N2的作业按b非增序排序,则N1作业接N2作业构成最优顺序。

    这个题目的思路:我们第一件物品加工b机器肯定会等,所以就让a机器开始加工的物品时间最短,而我们B机器最后加工完成肯定是A机器在等,所以让B机器最后加工完的时间尽可能短

    #include <bits/stdc++.h>
    using namespace std;
    const int N=10005;
    int a[N],b[N],s[N],m[N],ans[N],n,k,t; 
    void solve()
    {
        for(int i=1;i<=n;i++){m[i]=min(a[i],b[i]);s[i]=i;}
        for(int i=1;i<=n-1;i++)
            for(int j=i+1;j<=n;j++)
                if(m[i]>m[j]){swap(m[i],m[j]);swap(s[i],s[j]);}
        k=0;t=n+1;//k为A加工时间,t为B加工时间
        for(int i=1;i<=n;i++)
            if(m[i]==a[s[i]]){k++;ans[k]=s[i];}//就是N1类的,a<b
            else{t--;ans[t]=s[i];} //这种就是N2的,从后往前来
        k=0;t=0;
        for(int i=1;i<=n;i++)
        {
            k+=a[ans[i]];
            if(t<k) t=k;
            t+=b[ans[i]];
        } 
        cout<<t<<endl;//B机器结束的时间是结束的时间
        for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
        cout<<endl;
    }
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        for(int i=1;i<=n;i++) cin>>b[i];
        solve();
        return 0;
    }
    /*把所有任务分为两类
    1类ai<bi,2类ai>bi
    至于ai=bi放在哪一类均可,无影响,
    1类可按ai排序,ai小的靠前 
    2类按bi排序,bi小的靠后 
    安排后的结果一定是1类全部执行完再执行2类*/
    View Code

    1426:【例题5】智力大冲浪

    【题目描述】
    小伟报名参加中央电视台的智力大冲浪节目。本次挑战赛吸引了众多参赛者,主持人为了表彰大家的勇气,先奖励每个参赛者m元。先不要太高兴!因为这些钱还不一定都是你的。接下来主持人宣布了比赛规则: 首先,比赛时间分为n个时段(n≤500),它又给出了很多小游戏,每个小游戏都必须在规定期限ti前完成(1≤ti≤n)。如果一个游戏没能在规定期限前完成,则要从奖励费m元中扣去一部分钱wi,wi为自然数,不同的游戏扣去的钱是不一样的。当然,每个游戏本身都很简单,保证每个参赛者都能在一个时段内完成,而且都必须从整时段开始。主持人只是想考考每个参赛者如何安排组织自己做游戏的顺序。作为参赛者,小伟很想赢得冠军,当然更想赢取最多的钱! 注意:比赛绝对不会让参赛者赔钱!
    
    【输入】
    输入共4行。
    
    第一行为m,表示一开始奖励给每位参赛者的钱;
    
    第二行为n,表示有n个小游戏; 第三行有n个数,分别表示游戏1~n的规定完成期限;
    
    第四行有n个数,分别表示游戏1~n不能在规定期限前完成的扣款数。
    
    【输出】
    仅1行。表示小伟能赢取最多的钱。
    
    【输入样例】
    10000
    7
    4 2 4 3 1 4 6
    70 60 50 40 30 20 10
    【输出样例】
    9950
    【提示】
    数据范围及提示:
    
    n≤5001≤ti≤n
    1426:【例题5】智力大冲浪

    思路:

    先按罚款数额从大到小快排;顺序处理每个任务,若能安排,则找一个最晚时间,否则放在最后的空位上。

    #include <bits/stdc++.h>
    using namespace std;
    struct th
    {
        int a,b;
    }t[505];
    int pd[505];
    bool cmp(th x,th y)
    {
        return x.b>y.b;
    }
    int main()
    {
        int n,m,i,j;
        cin>>m;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>t[i].a;
        }
        for(int i=1;i<=n;i++)
        {
            cin>>t[i].b;
        }
        sort(t+1,t+1+n,cmp);
        for(i=1;i<=n;i++)
        {
            for(j=t[i].a;j>=1;j--)
            {
                if(pd[j]==0)
                {
                    pd[j]=1;
                    break;
                }
            }
            if(j==0)
                m-=t[i].b;
        }
        cout<<m<<endl;
        return 0;
    }
    View Code

    1427:数列极差

    思路:从小到大来的话就是最大值,从大到小来就是最小值;例如 1 2 3 ,(1*2+1)*3+1=10;(3*2+1)*1+1=8

    #include <bits/stdc++.h>
    using namespace std;
    int n,a[50005],ans,mod;
    priority_queue<int,vector<int>,greater<int> > q;//小根堆
    bool cmp(int a,int b){
        return a>b;
    }
    int findmax()
    {
        int temp;
        while(!q.empty())
        {
            temp=q.top();
            q.pop();
            temp=(temp*q.top()+1)%mod;
            q.pop();
            if(q.empty()) break;
            q.push(temp);
        }
        return temp;
    }
    int findmin() 
    {
        sort(a+1,a+1+n,cmp);
        int ans=a[1];
        for(int i=2;i<=n;i++)
            ans=(ans*a[i]+1)%mod;
        return ans;
    }
    int main()
    {
        cin>>n>>mod;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            q.push(a[i]);
        }
        int maxx=findmax();
        int minn=findmin();
        cout<<(maxx-minn)%mod<<endl;
        return 0;
    }
    View Code

    1428:数列分段

    #include <bits/stdc++.h>
    using namespace std;
    int a[100005];
    int main()
    {
        int n,m,i,sum=0,ans=1;
        cin>>n>>m;
        for(i=1;i<=n;i++)
        {
            cin>>a[i];
        }
        for(i=1;i<=n;i++)
        {
            if(sum+a[i]>m)
            {
                ans++;
                sum=0;
            }
            sum+=a[i];
        }
        cout<<ans<<endl;
        return 0;
    }
    View Code

    1429:线段

    思路:按着段尾从小到大进行排序,在来比较已经被选择的上一段的队尾和队首来进行比较就可以了

    #include <bits/stdc++.h>
    using namespace std;
    struct line
    {
        int a,b;
    }l[1000005];
    bool cmp(line x,line y)
    {
        return x.b<y.b;
    }
    int main()
    {
        int n,ans=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d %d",&l[i].a,&l[i].b);
        }
        sort(l+1,l+1+n,cmp);//按着段尾从小到大进行排序;
        int e=-1;
        for(int i=1;i<=n;i++)
        {
            if(l[i].a>=e)
            {
                ans++;
                e=l[i].b;
            }
         } 
         printf("%d
    ",ans);
        return 0;
    }
    View Code

    1430:家庭作业

    其实还是有点难,是一个贪心加上并查集的题目:根据学分从大到小进行排序,然后是进行一些并查集的操作,就看上一个时间

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1000005;
    struct node{
        int t,s;
    }stu[N];
    int n,flag,fa[N]; 
    bool cmp(node x,node y){
        if(x.s==y.s) return x.t<y.t;
        return x.s>y.s;
    }
    int find(int x){
        if(x<=0) return x;
        else if(x==fa[x]){
            fa[x]=x-1;
            flag=1;
            return fa[x];
        }
        else return fa[x]=find(fa[x]);
    }
    int main() {
        cin>>n;
        for(int i=1;i<=n;i++) scanf("%d %d",&stu[i].t,&stu[i].s);
        sort(stu+1,stu+1+n,cmp);
        for(int i=1;i<=n;i++) fa[i]=i;
        long long ans=0;
        for(int i=1;i<=n;i++){
            flag=0;
            fa[stu[i].t]=find(stu[i].t);
            if(flag) ans+=stu[i].s;
        }
        printf("%d
    ",ans);
        return 0;
    }
    /*
    7
    4 0
    4 5 7
    0
    5 6 0
    1 0
    1 0
    7 0
    0
    5 
    2 5 0
    0 
    2 4 0
    5 0
    0
    */
    View Code

    1431:钓鱼

    这个题目要用优先队列来做,要用到重载函数,主要的思路其实还是去枚举每个鱼塘作为最后一个鱼塘,那么根据贪心的思想,这个题目是肯定不会回头的,那么确定最后一个鱼塘之后,就按着最大的来,这个顺序不是最终的顺序,但是一定是把时间范围内能钓的最多的鱼都算进去了

    比如说     4 (1) 5(2) 6(1)     走路需要3个5分钟,一共12个5分钟,钓鱼的时间为9个五分钟

    1:6   还剩 4 5 5   2:5  4 5 4   3 5   4 3 4     ...这个不是钓鱼顺序

    #include <bits/stdc++.h>
    using namespace std;
    const int N=10005,inf=0x3f3f3f;
    struct node{
        int num,lose;
        bool operator <(node x)const{
            return num<x.num;
        }
    }a[N]; 
    int t[N],n,h,ans=0;
    priority_queue<node> q;
    int main()
    {
        cin>>n>>h;
        h*=12;//以5分钟为界限
        for(int i=1;i<=n;i++){ cin>>a[i].num;}
        for(int i=1;i<=n;i++){cin>>a[i].lose;}
        for(int i=1;i<=n-1;i++) cin>>t[i]; 
        for(int i=1;i<=n;i++){//枚举每个鱼塘作为最后一个 
            h-=t[i-1];
            int now=0;
            while(!q.empty()) q.pop(); //初始化
            for(int j=1;j<=i;j++) q.push(a[j]);//把以i为最后一个鱼塘的所有鱼塘加入
            for(int j=1;j<=h;j++)
            {
                node s=q.top();
                cout<<s.num<<endl;
                if(s.num>0) now+=s.num;
                s.num-=s.lose;
                q.pop();
                q.push(s);
            } 
            ans=max(now,ans);
        }
        cout<<ans<<endl;
        return 0;
    }
    View Code

    1432:糖果传递

    这个题目是一个数学的推导题:我们先求出最终每个人的平均值avr,直接给的就只有旁边两个人,我们统一一下来进行假设,给左边,从右边拿

    avr=a[1]-x1+x2    x2=avr-a[1]+x1   x2是右边给的,那么对于右边的小朋友来说,就是给左边的,所以

    avr=a[2]-x2+x3   x3=avr-a[2]+x2=avr-a[2]+avr-a[1]+x1

    ...

    avr=a[n]-xn+x1   无用

    用一个数组c[]表示 a[]-avr

    那么  x2=x1-c[1]   x3=x1-c[2]...c[2]=c[1]+a[]-avr;

    最后就是求x1+x2+x3+x4+...+xn

    又因为:x1+x1-c1+x2-c2+...+xn-1-cn-1

    我们希望Xi的绝对值之和尽量小,即|X1| + |X1-C1| + |X1-C2| + ……+ |X1-Cn-1|要尽量小。注意到|X1-Ci|的几何意义是数轴上的点X1到Ci的距离,所以问题变成了:给定数轴上的n个点,找出一个到他们的距离之和尽量小的点,而这个点就是这些数中的中位数

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=1000005,inf=0x3f3f3f;
    ll a[N],c[N],ans=0,n,sum=0,mid,avr;
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++){scanf("%lld",&a[i]);sum+=a[i];}
        avr=sum/n;
        for(int i=1;i<=n;i++){c[i]=c[i-1]+a[i]-avr;}
        sort(c,c+n);
        if(n&1){
            mid=c[n/2];
        }
        else{
            mid=(c[(n-1)/2]+c[(n-1)/2+1])/2;
        }//找中位数 
        for(int i=0;i<n;i++)
            ans+=abs(c[i]-mid); 
        printf("%lld
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    dropdownList级联刷新gridView
    Jquery解析json数据
    ASP.NET UserControl 通信
    sharepointWebPart开发、部署、发布过程全记录
    buffer和cache怎么让你们解释的那么难理解?
    Global.asax用法分析
    1、什么是ASP.NET MVC
    在Global.asax文件里实现通用防SQL注入漏洞程序
    ABP vNext V5 + VS2022+ .Net 6.0 学习笔记(1)
    使用IIS时的小问题
  • 原文地址:https://www.cnblogs.com/sunny99/p/12709443.html
Copyright © 2020-2023  润新知