20级课程作业-贪心算法 做题总结(二)

C
题目:x轴的上方有一些点代表岛,让你在x轴上找一些点安雷达,给你雷达的辐射范围(圆),求最少的雷达数。不行就输-1。

一开始我想的是先将岛分布最左和最右的两个点投影到坐标轴上,然后在这个范围内求每个x轴点的辐射范围,如果这个点尽可能能包含较多的点就取这个点,但这样写一方面可能会超时,另一方面,处理起来代码会很复杂,不好优化,而且容易求多点,所以这种方法不可取。
如果换一个方面想,不找雷达的辐射范围,改为找岛能收到信号的范围,这样就可以把每个岛转化成x轴上的一些区间,问题就变成了求区间交集问题。基本套路,先对区间前一个点从小到大排序,指针指向第一个区间的末点,与第二个区间首点或者末点比较,更新指针位置。
注意先判断是否可安雷达,以及输入和输出要求

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
struct point
{
    
    
    double x,y;
    bool operator<(const point &b)const
    {
    
    
        return x<b.x;
    }
} num[1005];
int main()
{
    
    
    int n,d,i,sum=1,a,b,p=1;
    double r;
    while(cin>>n>>d)
    {
    
       sum=1;
        if(n==0&&d==0)
            break;
        for(i=0; i<n; i++)
        {
    
       cin>>a>>b;
            if(b>d)
            {
    
    
                sum=-1;
            }
            num[i].x=a-sqrt((double)(d*d-b*b));
            num[i].y=a+sqrt((double)(d*d-b*b));
        }
        if(sum!=-1)
        {
    
       sort(num,num+n);
            r=num[0].y;
            for(i=1; i<n; i++)
            {
    
    
                if(r<num[i].x)
                {
    
    
                    sum++;
                    r=num[i].y;
                }
                else if(num[i].y<r)
                {
    
    
                    r=num[i].y;
                }
            }
        }
        cout<<"Case "<<p++<<": "<<sum<<endl;
    }
    return 0;
}

H
题意:给你n个木头的长度和重量,先进行一下操作,若下一个木头的长度和重量大于等于前一个的长度和重量,就继续,否则加1分钟重置,求最少重置时间。

这个问题的关键点在于大于等于,因此需先对木头的长度和重量排序,但长度重量不能同时满足递增,所以先对其中一个排序,根据这个顺序只需考虑另一个变量。当我们把另一个变量按照先定义的排序顺序排列,我们要让下一个元素大于前一个,求最少时间,很容易发现,这个问题就转化成了给你一组数,让你从前开始找出后面递增的序列,求有多少组,我们只需从第一个数开始,找到后面大于第一个数的递增数就删去,再从第二个数继续找,直到找完,求组数即可,此题方法比较巧妙,转化后题目较易

#include<iostream>
#include<algorithm>
using namespace std;
struct n
{
    
    
    int l,w;
    bool operator < (const n &b)const
    {
    
    
        return l<b.l||l==b.l&&w<b.w;
    }
} num[5005];
int main()
{
    
    
    int t;
    cin>>t;
    while(t--)
    {
    
    
        int n,i,d=0,j,p=0;
        cin>>n;
        for(i=0; i<n; i++)
            cin>>num[i].l>>num[i].w;
        sort(num,num+n);
        for(i=0; i<n; i++)
        {
    
    
            if(num[i].w!=0)
            {
    
    
                d++;
                p=num[i].w;
                for(j=i+1; j<n; j++)
                {
    
    
                    if(num[j].w>=p)
                    {
    
    
                        p=num[j].w;
                        num[j].w=0;
                    }
                }
            }
        }
        cout<<d<<endl;
    }
    return 0;
}

I
题目:n个人玩牌,每个人给m张牌,所有牌按从1~n*m标号,如果你比别人出牌大,你就赢,直到一个人m张牌全部打出停止,求你至少能赢的最大局数。

这个题题意很容易理解,解题思路很明确,就是找除了你的牌以外在没打出的牌中找最大的,与你的牌比较。处理过程的方式也很多,我的做法是,在你除了的牌之中找前m个大牌存入一个数组,将这个数组与排过序的你的牌数组比较,找你能赢的次数,另一种方式是对你的牌和出的牌标记,在没出的牌中找最大的与你没出的牌比较,基本思路是一样的。

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

int main()
{
    
    
    int m,n,i,c,a[55],q=1,p,j,b[55]= {
    
    0};
    while(cin>>m>>n&&(m!=0&&n!=0))
    {
    
       int d=0;
        for(i=0; i<n; i++)
        {
    
       cin>>a[i];
        }
        sort(a,a+n);
        p=m*n;
        c=n;
        for(i=n-1; i>=0; i--)
        {
    
    
            while(p==a[c-1])
            {
    
    
                p--;
                c--;
            }
            b[i]=p;
            p--;
        }
        sort(b,b+n);
        c=n-1;
        for(i=n-1; i>=0; i--)
        {
    
    
            if(a[i]>b[c])
            {
    
    
                d++;
            }
            else c--;
        }
        cout<<"Case "<<q++<<": "<<d<<endl;
    }
    return 0;
}

k
题意:给你一堆电视节目播出时间表,求你最多能看几个节目。

这个题比较典型,可以转化为区间不覆盖问题,基本套路是对不同区间的右端点排序,标记第一个区间的末点,如果下一个区间的首点大于等于前一个区间的末点,就可看,更新指针为现在区间的末点。这个题可看成一种固定的解题套路。

#include<iostream>
#include<algorithm>
using namespace std;
struct jm
{
    
    
    int begin,end;
    bool operator <(const jm &b) const {
    
    
        return end<b.end;
    }
} num[101];
int main()
{
    
    
    int n,i;
    while(cin>>n&&n)
    {
    
    
        for(i=0; i<n; i++)
            cin>>num[i].begin>>num[i].end;
        sort(num,num+n);
        int r,sum=1;r=num[0].end;
        for(i=1; i<n; i++)
        {
    
    
            if(num[i].begin>=r)
            {
    
       sum++;
                r=num[i].end;
            }
        }
        cout<<sum<<endl;
    }
    return 0;
}

G
问题:走廊南北向的两边各有200个房间。走廊里一次只能通过一张办公桌。一张办公桌从一个房间移到另一个房间最多用十分钟。当从房间i移动一张办公桌到房间j,两个办公室之间的走廊都会被占用。所以,每10分钟内,只要不是同一段走廊,都可以在房间之间移动办公桌。给你搬桌次数和搬桌房间,求最少时间

这个题题目较长,先将题干的关键部分画出,这是一个典型的标记题,注意初始移动房间和移动后房间在走廊的位置,将那段走廊标记,标记多的数就是移动次数。这个题关键是要将房间号转化为走廊号,进而就能较好的找到解决问题的思路。

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

int main()
{
    
    
    int t;
    cin>>t;
    while(t--)
    {
    
    
        int n,a,b,i,j;
        int m[200]= {
    
    0};
        cin>>n;
        for(i=0; i<n; i++)
        {
    
    
            cin>>a>>b;
            a=(a-1)/2;
            b=(b-1)/2;
            if(a>b)
                swap(a,b);
            for(j=a; j<=b; j++)
            {
    
    
                m[j]++;
            }
        }
        sort(m,m+200);
        cout<<m[199]*10<<endl;
    }
    return 0;
}

P
题目:给你n组数据,每组包括一个人的速度和出发时间(有正负),你要走4.5千米,必须跟着人一起走,如果在一段时间内没有人,你就要等人到达你所在位置,如果你在走的过程中另一个人超过了你,你就要跟着速度快的那个人。求你到达目的地的最少时间。

首先先分析题目,题目给出了其他人的出发时间,以你出发的时间为0计算,当时间为负时,说明这个人在你出发之前就已经出发了,所以这个人的数据无用,可通过输入数据时删除。再分析过程,假设你先跟一个人走了一段距离,这时另一个人从起点开始出发,过了一段时间后那个晚出发的人追上了你,下一步你要跟着晚出发的速度快点那个人走,分析前面的过程发现可以列一个等式,到第二个人撵上为止,你跟着第一个走的时间与第二个人撵上你所花的时间一致,所以你先跟着第一个人走再跟着第二个人走一共花的时间可以直接看成你跟着第二个人走花的时间加上第二个人出发的时间。同理,如果跟了三个人,也可以求时间为第三个人到终点花的时间加上他出发的时间。你只需将每个人到终点的时间求出,找最短的即可。
注意,计算除法时要转化为double类型,最后结果要转化为整数,并且需要用ceil向上取整

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
struct X
{
    
    
    double v,t;
    bool operator < (const X &b)const
    {
    
    
        return v<b.v;
    }
} a[10005];
int main()
{
    
    
    int n,i;
    while(cin>>n&&n!=0)
    {
    
       
        for(i=0; i<n; i++)
        {
    
       cin>>a[i].v>>a[i].t;
            if(a[i].t<0)
            {
    
       i--;
                n--;
            }
            else a[i].v=a[i].t+(4.5/a[i].v)*3600;
        }
        sort(a,a+n);
        cout<<ceil(a[0].v)<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_51443397/article/details/115018046