Some greedy question explanations

As we all know, it is a more disgusting greedy algorithm.

Different from the conventional algorithms or data structures, greedy people see problems generally do not think of the idea, but we need some speculation or inductive analysis, to find a local optimum solution, and can be a local optimum Solutions to launch global optimal solution.

 

T1: Sunscreen

There sunbathing C cows, cows need to i-th minSPF [i] to maxSPF [i] between the unit light intensity.

Each cow must be painted before tanning sunscreen, sunscreen L-species, painted after the i-th, the body of the received light intensity of the SPF will stabilize [i], the i-th sunscreens have Cover [i] Bottle .

Seeking to meet the most number of cows sunbathing.

Input Format

The first line of the input integer C and L.

The next line C, in sequence each input line and a cow minSPF maxSPF values, i.e. i-th row input minSPF [i] and maxSPF [i].

The next line of the L, in sequence each input line and one kind of cover sunscreen SPF values, i.e., the i-th row input SPF [i] and the cover [i].

Separated by spaces between each row of data.

Output Format

Output an integer representing the largest number of cows to meet the cows sunbathing.

data range

1C,L25001≤C,L≤2500,
1minSPFmaxSPF10001≤minSPF≤maxSPF≤1000,
1SPF10001≤SPF≤1000

Sample input:

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

Sample output:

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开始,只要方案合法即可。

数据范围

1N500001≤N≤50000,
1A,B10000001≤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”。

数据范围

1n10001≤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;
}
 

 

 

Guess you like

Origin www.cnblogs.com/ABBEJ/p/11286149.html