0
点赞
收藏
分享

微信扫一扫

贪心算法_记

楠蛮鬼影 2022-04-29 阅读 71

贪心算法

(无模板)

区间问题:
例题:区间选点
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1e5+10;
int n;

struct node{
    int l,r;
    const bool operator < (const node &a) const{
        return r<a.r;
    }
}eg[N];

int main()
{
    cin >> n;
    for(int i=0;i<n;i++)
    {
        int a,b;
        cin >> a >> b;
        eg[i]={a,b};
    }
    sort(eg,eg+n);
    int res=0,ed=-2e9; //取一个比所有的值都要小的数,使能取到第一条线段
    for(int i=0;i<n;i++)
    {
        if(eg[i].l>ed){
            res++;
            ed=eg[i].r;
        }
    }
    cout << res << endl;
    return 0;
}

按右端点排序,每次找前一个线段的左端点严格小于下一个的右端点的线段,得到的所有线段都是严格没有相交部分的,也就是互相独立的部分,每一部分可能有不同数量的线段组成,严格独立的部分的数量就是 最少的选点的数量。

例题:最大不相交区间数量

给定 N N N个闭区间 [ a i , b i ] [ai,bi] [ai,bi],请你在数轴上选择若干区间,使得选中的区间之间互不相交(包括端点)。

输出可选取区间的最大数量。

思路代码同上

例题:区间分组

(感觉稍稍有点难,不太好想,没想到用到优先队列,还有里面的相关处理)

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

const int N = 1e5+10;

int n;
struct node{
    int l,r;
    const bool operator < (const node&a) const {
        return l<a.l;
    }
}eg[N];

int main()
{
    cin >> n;
    for(int i=0;i<n;i++)
    {
        int a,b;
        cin >> a >> b;
        eg[i]={a,b};
    }
    sort(eg,eg+n);
    priority_queue<int,vector<int>,greater<int>>pq;//小根堆
    for(int i=0;i<n;i++)
    {
        auto t=eg[i];
        if(pq.empty()||pq.top()>=t.l) pq.push(t.r);//如果当前集合内的右端点的最小值与当前线段有重合,那么把当前集合的右端点加进集合
                                          //也说明组数加一
        else{//否则说明 可以在同一组 那么组合数不需要再加一,而是把这个可以相容的组合的信息更新,即把右端点更新
            pq.pop();
            pq.push(t.r);
        }
    }
    cout << pq.size() << endl;
    return 0;
}
例题:区间覆盖

(思想与上一题相似)

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

const int N = 1e5+10;
int n,st,ed;
struct node{
    int l,r;
    const bool operator<(const node&a)
    {
        return l<a.l;
    }
}eg[N];

int main()
{
    cin >> st >> ed >> n;
    bool can=0;
    for(int i=0;i<n;i++)
    {
        int a,b;
        cin >> a >> b;
        eg[i]={a,b};
    }
    sort(eg,eg+n);
    int res=0;
    for(int i=0;i<n;i++)
    {
        int j=i,dd=-2e9;
        while(j<n&&eg[j].l<=st){
            dd=max(dd,eg[j].r);
            j++;
        }
        if(dd<st) break;//若前一个区间右端点的最大值都小于下一个区间的左端点,那么一定无解
        res++;//否则区间数加一
        if(dd>=ed) {//如果此时所选区间右端点已经满足题意那么也直接结束
            can=1;//标记一下是成功了才结束的
            break;
        }
        st=dd;//更新区间右端点
        i=j-1;//细节:while结束时j是第一个不满足条件的
    }
    if(!can) res=-1;
    cout << res << endl;
    return 0;
}
H u f f m a n Huffman Huffman
例题:合并果子
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;

const int N = 10010;

int n;

int main()
{
    cin >> n;
    priority_queue<int,vector<int>,greater<int>>pq;
    while(n--){
        int a;
        cin >> a;
        pq.push(a);
    }
    int res=0;
    while(pq.size()>1){
        int a=pq.top();
        res+=a,pq.pop();
        int b=pq.top();
        res+=b,pq.pop();
        //res+=a+b;
        pq.push(a+b);//注意这里不是将res加进去
    }
    cout << res << endl;
    return 0;
}
排序不等式
例题:排队打水
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 1e5+10;
int n;
int t[N];

int main()
{
    cin >> n;
    for(int i=0;i<n;i++) cin >> t[i];
    sort(t,t+n);
    ll res=0;
    for(int i=0;i<n;i++){
        res+=t[i]*(n-i-1);
    }
    cout << res << endl;
    return 0;
}

证明:

等待时间之和= t 1 × ( n − 1 ) + t 2 × ( n − 2 ) + ⋯ + ( t n − 1 × 1 + t n × 0 t_1\times (n-1)+t_2\times (n-2)+\dots + (t_{n-1}\times 1+t_n\times 0 t1×(n1)+t2×(n2)++(tn1×1+tn×0

所以将排队打水的时间从小到大排序。。。

绝对值不等式
例题:仓库选址

(小学奥数题,选最中间的点)

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

using namespace std;

const int N = 1e5+10;
int a[N];
int main()
{
    int n; cin >> n;
    for(int i=0;i<n;i++) cin >> a[i];
    sort(a,a+n);
    int dis=0;
    int mid=a[n/2];//中位点
    for(int i=0;i<n;i++) dis+=abs(a[i]-mid);
    cout << dis << endl;
    return 0;
}
推公式
例题:耍杂技的牛
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 5e4+10;
typedef pair<int,int>PII;
PII p[N];

int main()
{
    int n; cin >> n;
    for(int i=0;i<n;i++)
    {
        int w,s;
        cin >> w >> s;
        p[i]={w+s,s};
    }
    sort(p,p+n);
    int res=-2e9,sum=0;
    for(int i=0;i<n;i++)
    {
        int s=p[i].second,w=p[i].first-s;
        res=max(res,sum-s);
        sum+=w;
    }
    cout << res << endl;
    return 0;
}

w i + s i w_i+s_i wi+si从小到大排序,小的在上大的在下。


小结:

贪心算法…就是猜

难的主要是证明,好猜但不好证,或者说不好猜也不好证。。。

举报

相关推荐

0 条评论