0x07yp

本文详细介绍了贪心算法在解决POJ(在线判题系统)中的多个问题的应用,包括防晒霜分配、草地喂牛、雷达覆盖范围优化等。通过排序和优先级队列等数据结构,实现不同场景下的最优解策略。同时,文章还讨论了一个错误的贪心策略并给出了正确的解决方案,展示了贪心算法在实际问题中的灵活运用。
摘要由CSDN通过智能技术生成

POJ3614

思路1

按照minSPF递减排序,依次考虑每头奶牛
对于每头奶牛,扫描一遍所有的防晒霜,在这头奶牛呢
能用的范围内,并且瓶数还有剩余时候找到最大SPF值使用
每一瓶是否可以被使用,取决于minSPF和maxSPF条件限制
每一个不低于当前奶牛的minSPF的防晒霜,
都不会低于后面一个奶牛的minSPF
对于当前奶牛可以使用的任意两瓶防晒霜x<y
要么xy均可使用(后牛的maxSPF处于xy值上方),
xy均不可使用(后牛的maxSPF处于xy值下方),
如果(后牛的maxSPF处于xy值中间)则x可用,y不可用
所以当前的牛选择y对整体比较好
而且每头牛对整体的贡献都是1,所以放弃使用给后面的
牛使用也不回对整体变的更大

AC1

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define db double
#define pii pair<int, int>
#define psi pair<string, int>
#define ull unsigned ll
#define pb push_back
#define mp make_pair
#define ld long double
#define X first
#define Y second
const int N = 2555 + 7;
#define INF ~0ULL
int n, m;
pii a[N];
pii b[N];
int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> a[i].first >> a[i].second;
    for (int i = 1; i <= m; i++)
        cin >> b[i].first >> b[i].second;
    sort(a + 1, a + 1 + n, greater<pii>());
    sort(b + 1, b + 1 + m, greater<pii>());
    int ans = 0;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            if (a[i].X <= b[j].X && a[i].Y >= b[j].X && b[j].Y)
            {
                ans++;
                b[j].Y--;
                break;
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

思路2

那么将奶牛按照阳光强度的最小值从小到大排序。
将防晒霜也按照能固定的阳光强度从小到大排序
从小的防晒霜枚举,将所有符合 最小值小于等于该防晒霜的奶牛的最大值放于优先队列中
然后从优先对列中取出较小值比较是否满足maxSPF>=spf
如果牛的最大值小于最小防晒霜就舍弃次牛

AC2

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define db double
#define pii pair<int, int>
#define psi pair<string, int>
#define ull unsigned ll
#define pb push_back
#define mp make_pair
#define ld long double
#define X first
#define Y second
const int N = 2555 + 7;
#define INF ~0ULL
int n, m;
pii a[N];
pii b[N];
priority_queue<int, vector<int>, greater<int>> q;
int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> a[i].first >> a[i].second;
    for (int i = 1; i <= m; i++)
        cin >> b[i].first >> b[i].second;
    sort(a + 1, a + 1 + n);
    sort(b + 1, b + 1 + m);
    int ans = 0, j = 1;
    for (int i = 1; i <= m; i++)
    {
        while (j <= n && a[j].X <= b[i].X)
        {
            q.push(a[j].Y);
            j++;
        }
        while (!q.empty() && b[i].Y)
        {
            int x = q.top();
            q.pop();
            if (x < b[i].X)
                continue;
            ans++;
            b[i].Y--;
        }
    }
    cout << ans << endl;
    //system("pause");
    return 0;
}

POJ3190

思路

按照牛开始吃草的时间排序
对于每头牛,如果有空位置就到最到先
离开的那头牛的位置吃草,没有就新开一个

AC

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define db double
#define pii pair<int, int>
#define psi pair<string, int>
#define ull unsigned ll
#define pb push_back
#define mp make_pair
#define X first
#define Y second
#define ld long double
const int N = 5E5 + 7;
#define INF ~0ULL
priority_queue<int, vector<int>, greater<int>> q;
int n;
pii niu[N];
int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> niu[i].X >> niu[i].Y;
    sort(niu + 1, niu + 1 + n);
    q.push(niu[1].Y);
    int ans = 1;
    for (int i = 2; i <= n; i++)
    {
        int x = q.top();
        q.pop();
        if (x <= niu[i].X)
            q.push(niu[i].Y);
        else
        {
            ans++;
            q.push(x);
            q.push(niu[i].Y);
        }
    }
    cout << ans << endl;
}

POJ1328

链接: link.

思路

先将坐标转换成雷达区间,然后就是每个区间至少一个点的最小点数

AC

#include <bits/stdc++.h>
using namespace std;

struct Node
{
    double Left, Right;
} s[1010];

bool cmp(Node x, Node y)
{
    return x.Left < y.Left;
}

int main()
{
    int n, d;
    int time = 0;
    while (cin >> n >> d && (n != 0 || d != 0)) //这个n d不同时0的条件错了几次,刚开始写成&&了,那样的话是都不能为0。
    {
        time++;
        double x, y;
        double l;
        int p = 1;//flag
        for (int i = 0; i < n; i++)
        {
            cin >> x >> y;
            if (y > d && p)
                p = 0;
            else //存能覆盖该小岛的圆心所在的区间
                l = sqrt(d * d * 1.0 - y * y), s[i].Left = x - l, s[i].Right = x + l;
        }
        if (p)
        {
            int sum = 1;
            sort(s, s + n, cmp);
            double now = s[0].Right;
            for (int i = 1; i < n; i++)
            {
                if (s[i].Left > now)
                    sum++,
                        now = s[i].Right;
                else if (s[i].Right < now)
                    now = s[i].Right;
            }
            cout << "Case " << time << ": " << sum << endl;
        }
        else
            cout << "Case " << time << ": -1" << endl;
    }
    return 0;
}

NOIP2012/CH0701

链接: link.

POJ2054

思路

错误的贪心:每一步都在可以被染色的点里选择权值最大的染色,
读者很容易构造出其反例,只要构造出一棵树,让一个权值很小的
节点下边很多权值巨大的节点,另一个权值较大的点却没有子节点
从这个错误的贪心中想到,我们可以提取出一个正确的性质,树中
除根节点权值最大的点,一定会在他的父节点被染色后立即染色
于是我们可以确定的是,树中权值最大的点及其父节点的染色操作是
连续进行的,我们可以把这两个点“合并起来”,合并得到的新点的权值
设为这两个点的权值的平均值。
例如:有xyz的三个点,我们已知x和y的染色操作是连续进行的,那么
就有两种可能的染色方案:
1,先x,y再z 代价x+2y+3z
2,先z,再x,y 代价z+2x+3y
同时加上(z-y)
1,x+y+4z
2, 2z+2x+2y
除以二
1,(x+y)/2+2z
2, z+2*((x+y)/2)
这恰好就相当于有权值为(x+y)/2和z的两个点的两种染色次序。换
言之,下一列两种情况的最优染色次序可以互相转化
1,权值为x,y,z的三个点。
2, 权值为(x+y)/2和z的两个点
进一步推近,我们可以得到一种“等效权值”的算法,记录每
个点是由多少点合并而成的,一个点的“等效权值”定义为:
该点包含的原始权值总和/该点包含的原始点数

AC

别人的链接

链接: link.
链接: link.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

.0-0.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值