一些贪心题的题解

众所周知,贪心是一个比较恶心的算法。

区别于常规的算法或数据结构,贪心题一般不会让人看到就想到思路,而是需要我们在一些猜测或是感性分析下,找到一种局部最优的方案,并且可以通过局部最优解推出全局最优解。

T1:防晒

有C头奶牛进行日光浴,第i头奶牛需要minSPF[i]到maxSPF[i]单位强度之间的阳光。

每头奶牛在日光浴前必须涂防晒霜,防晒霜有L种,涂上第i种之后,身体接收到的阳光强度就会稳定为SPF[i],第i种防晒霜有cover[i]瓶。

求最多可以满足多少头奶牛进行日光浴。

输入格式

第一行输入整数C和L。

接下来的C行,按次序每行输入一头牛的minSPF和maxSPF值,即第i行输入minSPF[i]和maxSPF[i]。

再接下来的L行,按次序每行输入一种防晒霜的SPF和cover值,即第i行输入SPF[i]和cover[i]。

每行的数据之间用空格隔开。

输出格式

输出一个整数,代表最多可以满足奶牛日光浴的奶牛数目。

数据范围

1≤C,L≤25001≤C,L≤2500,
1≤minSPF≤maxSPF≤10001≤minSPF≤maxSPF≤1000,
1≤SPF≤10001≤SPF≤1000

输入样例:

3 2
3 10
2 5
1 5
6 2
4 1

输出样例:

2

不难想到,该题的贪心策略为:1.将所有奶牛的maxSPF从大到小排序。2.枚举每一头奶牛,选择可选防晒霜中SPF值最大的一个使用。

证明:1.如果把所有奶牛与防晒霜的SPF值都看成点,那么这个题实际上就是一个二分图的最大匹配问题。2.根据匈牙利算法,如果已匹配的二分图中不存在增广路,那么这就是一个最大匹配的二分图。3.如果以我们的算法不可以找到最短增广路,那么此算法即为正解4.如果以一个防晒霜a的SPF值为起点,那么根据算法可以看出,下一个增广路径中的防晒霜的SPF值b一定在a所匹配的奶牛的SPF区间的右侧。5.那么就可以根据增广路径的最短性得知增广路径只能从奶牛maxSPF由小到大去得到。6.如果我们找到了最短增广路,那么此时具有最大maxSPF的奶牛没有点匹配,而具有第二大maxSPF的奶牛有点匹配,与算法矛盾。7.该算法正确。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=2510;
typedef pair<int,int> PII;
PII cow[N],cover[N];
int C,L;

int main() {
    cin>>C>>L;
    for (int i=0;i<C;++i)
        cin>>cow[i].first>>cow[i].second;
    for (int i=0;i<L;++i)
        cin>>cover[i].first>>cover[i].second;
    sort(cow,cow+C);
    int ans=0;
    for (int i=C-1;i>=0;--i) {
        int max_cover=0,p;
        for (int j=0;j<L;++j)
            if (cover[j].first>=cow[i].first&&cover[j].first<=cow[i].second&&max_cover<cover[j].first)
                max_cover=cover[j].first,p=j;
        if (max_cover!=0) {
            ans++;
            cover[p].second--;
            if (cover[p].second==0) cover[p].first=0;
        }
    }
    cout<<ans;
    return 0;
}



T2.畜栏预定

有N头牛在畜栏中吃草。

每个畜栏在同一时间段只能提供给一头牛吃草,所以可能会需要多个畜栏。

给定N头牛和每头牛开始吃草的时间A以及结束吃草的时间B,每头牛在[A,B]这一时间段内都会一直吃草。

当两头牛的吃草区间存在交集时(包括端点),这两头牛不能被安排在同一个畜栏吃草。

求需要的最小畜栏数目和每头牛对应的畜栏方案。

输入格式

第1行:输入一个整数N。

第2..N+1行:第i+1行输入第i头牛的开始吃草时间A以及结束吃草时间B,数之间用空格隔开。

输出格式

第1行:输入一个整数,代表所需最小畜栏数。

第2..N+1行:第i+1行输入第i头牛被安排到的畜栏编号,编号从1开始,只要方案合法即可。

数据范围

1≤N≤500001≤N≤50000,
1≤A,B≤10000001≤A,B≤1000000

输入样例:

5
1 10
2 4
3 6
5 8
4 7

输出样例:

4
1
2
3
2
4

更不难想到,此题的贪心做法:1.将每头牛吃草的起始时间A排序。2.枚举每一头牛,若此时所有畜栏的最小吃草末尾时间<该牛的起始时间,就另增一个畜栏,并保存末尾时间。

证明:1.根据此算法得出的方案中的所有畜栏不存在任意两个之间没有交集。2.所以最优解>=求得的方案。3.又因为最优解<=求得的方案。4.该算法正确。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int N=50010;
typedef pair<int,int> PII;
pair<PII,int> cow[N];
int n,mark[N];

int main() {
    cin>>n;
    for (int i=0;i<n;++i) {
        cin>>cow[i].first.first>>cow[i].first.second;
        cow[i].second=i;
    }
    sort(cow,cow+n);
    priority_queue< PII,vector<PII>,greater<PII> > heap;
    for (int i=0;i<n;++i)
        if (heap.empty()||cow[i].first.first<=heap.top().first) {
            PII stall=make_pair(cow[i].first.second,heap.size()+1);
            heap.push(stall);
            mark[cow[i].second]=stall.second;
        }
        else {
            mark[cow[i].second]=heap.top().second;
            PII stall=make_pair(cow[i].first.second,heap.top().second);
            heap.pop();
            heap.push(stall);
        }
    cout<<heap.size()<<endl;
    for (int i=0;i<n;++i) cout<<mark[i]<<endl;
    return 0;
}



T3.雷达设备

假设海岸是一条无限长的直线,陆地位于海岸的一侧,海洋位于另外一侧。

每个小岛都位于海洋一侧的某个点上。

雷达装置均位于海岸线上,且雷达的监测范围为d,当小岛与某雷达的距离不超过d时,该小岛可以被雷达覆盖。

我们使用笛卡尔坐标系,定义海岸线为x轴,海的一侧在x轴上方,陆地一侧在x轴下方。

现在给出每个小岛的具体坐标以及雷达的检测范围,请你求出能够使所有小岛都被雷达覆盖所需的最小雷达数目。

输入格式

第一行输入两个整数n和d,分别代表小岛数目和雷达检测范围。

接下来n行,每行输入两个整数,分别代表小岛的x,y轴坐标。

同一行数据之间用空格隔开。

输出格式

输出一个整数,代表所需的最小雷达数目,若没有解决方案则所需数目输出“-1”。

数据范围

1≤n≤10001≤n≤1000

输入样例:

3 2
1 2
-3 1
2 1

输出样例:

2

算法:把所有岛屿的x轴上可监测区间求出。把所有区间的末端点排序。枚举每一个区间,若第i*区间初端点被第i区间末端点包含,方案数+1,并保存新的末端点。

证明:该算法得出的每个方案中的首区间两两不存在交集,因此得证。

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef pair<double,double> PII;
const int N=1010;
PII len[N];

bool cmp(PII x,PII y) {
    return x.second<y.second;
}

int main() {
    int n;
    double d;
    cin>>n>>d;
    for (int i=0;i<n;++i) {
        cin>>len[i].first>>len[i].second;
        int x=len[i].first,y=len[i].second;
        if (y>d) {cout<<-1; return 0;}
        len[i]=make_pair(x-sqrt(d*d-y*y),x+sqrt(d*d-y*y));
    }
    sort(len,len+n,cmp);
    int ans=1;
    double p=len[0].second;
    for (int i=1;i<n;++i)
        if (len[i].first>p) ++ans,p=len[i].second;
    cout<<ans;
}

 

原文地址:https://www.cnblogs.com/ABBEJ/p/11286149.html

时间: 2024-10-09 06:06:55

一些贪心题的题解的相关文章

【ZROI 537】贪心题 题解

[ZROI 537]贪心题 题解 Link Solution 最大的一边直接放到一起贪心即可 着重讲小的一边 已知对于二分图匹配,其答案即为最大流 令时间集合为 \(T = {1,2,3,\dots,maxt}\) 对于每一门课程,按照如下方式建图: 每个任务为一个点,每个时间为一个点,每个任务向其对应的时间区间连边,源点向每个任务连边,边权为 \(1\),每个时间向汇点连边,边权为 \(1\) 考虑第一门课程: 我们选择一些时间节点分给它,设为 \(T_1\) 假设最大流中任务集合为 \(A\

贪心(qwq)习题题解

贪心(qwq)习题题解 SCOI 题解 [ SCOI2016 美味 ] 假设已经确定了前i位,那么答案ans一定属于一个区间. 从高位往低位贪心,每次区间查找是否存在使此位答案为1的值. 比如6位数确定了前三位\((101...)_2\),下一位应该是1 那么\(a_i+x_i\)的查找区间为:\([(101100)_2,(101111)_2]\) ,同理如果应该是0则为\([(101000)_2,(101011)_2]\). 注意到有区间\([l,r]\)范围的限制所以用主席树维护即可. [

网易2017春招笔试真题编程题集合题解

01 双核处理 题目 一种双核CPU的两个核能够同时的处理任务,现在有n个已知数据量的任务需要交给CPU处理,假设已知CPU的每个核1秒可以处理1kb,每个核同时只能处理一项任务.n个任务可以按照任意顺序放入CPU进行处理,现在需要设计一个方案让CPU处理完这批任务所需的时间最少,求这个最小的时间. 输入描述 输入包括两行:第一行为整数n(1 ≤ n ≤ 50)第二行为n个整数lengthi,表示每个任务的长度为length[i]kb,每个数均为1024的倍数. 输出描述输出一个整数,表示最少需

杭电 2187 (贪心题)悼念512汶川大地震遇难同胞——老人是真饿了

http://acm.hdu.edu.cn/showproblem.php?pid=2187 悼念512汶川大地震遇难同胞--老人是真饿了 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 7286    Accepted Submission(s): 3043 Problem Description 时间:2008年5月16日(震后第4

Codeforces Round #631 (Div. 2) C. Dreamoon Likes Coloring(贪心好题/意识流题解)

Dreamoon likes coloring cells very much. There is a row of nn cells. Initially, all cells are empty (don't contain any color). Cells are numbered from 11 to nn . You are given an integer mm and mm integers l1,l2,…,lml1,l2,…,lm (1≤li≤n1≤li≤n ) Dreamoo

hdu 1052 Tian Ji -- The Horse Racing 可恶的贪心-------也算是经典贪心题吧,对于一般人来说,不看题解,应该很难做出来吧

Tian Ji -- The Horse Racing Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 20051    Accepted Submission(s): 5869 Problem Description Here is a famous story in Chinese history. "That was about

9.18考试 第二题Dinner题解

当时初步感觉是一个类似动归或者贪心的神题,然而由于本题已经给出顺序,贪心貌似并没有什么道理,所以放弃贪心.然后又由于这是一个环的问题,我想到了"合并石子"那种环转链的思路,然后就是一个O(n^2*m)的近似背包的打法,虽然没有去打,但应该可行吧-- 然后我又发现这道题貌似可以二分答案来进行check,然后我们就需要去枚举每一次的起始点,并进行模拟,然后加了一个剪枝即如果当前点的前缀和大于当前check的值,说明我们已经在给第一个点第一份菜单时给了他第二份菜单,而这又是不可行的,否则我们

【网络流24题】----题解(部分,持续更新...)

搭配飞行员 搭配飞行员:http://cogs.yeefan.us/cogs/problem/problem.php?pid=14 题解:建立虚拟源点汇点,然后水过 code:http://cogs.yeefan.us/cogs/submit/code.php?id=148410 数字梯形 数字梯形:http://cogs.yeefan.us/cogs/problem/problem.php?pid=738 题解: 规则(1) 把梯形中每个位置抽象为两个点(i.a),(i.b),建立附加源S汇T

长理 校赛的 一个贪心题

cls与lzp的热身赛 发布时间: 2017年12月11日 13:58   最后更新: 2017年12月11日 14:46   时间限制: 1000ms   内存限制: 128M 描述 众所周知,长春理工大学的"嗨呀好气啊"队伍由两个菜鸡lzp和cls以及某X姓巨巨组成,热身赛打的太好可能导致电脑里的PC^2被删掉,所以热身赛一般都是由lzp和cls两个菜鸡代表队伍参加比赛,热身赛由n道题组成,他们队内分工明确,lzp想出思路,然后cls去写,第i个题目lzp思考出来的是第ai分钟,c