信息学奥赛一本通 1927:【04NOIP普及组】花生采摘 | OpenJudge NOI 1.13 38:花生采摘 | 洛谷 P1086 [NOIP2004 普及组] 花生采摘

【题目链接】

ybt 1927:【04NOIP普及组】花生采摘
OpenJudge NOI 1.13 38:花生采摘
洛谷 P1086 [NOIP2004 普及组] 花生采摘

【题目考点】

1. 模拟
2. 贪心

【解题思路】

该题一定要仔细看题,题目中有:

鲁宾逊先生说:“你先找出花生最多的植株,去采摘它的花生;然后再找出剩下的植株里花生最多的,去采摘它的花生;依此类推,不过你一定要在我限定的时间内回到路边。”

所以不是我们决定一条能够采花生的路线,而是这个鲁宾逊已经指定了采花生的顺序,狗只能按照他给的贪心的思路不断采有花生最多的植株。我们只需要判断什么时候要让狗停止采摘回到路边。
设变量t表示已经用过的时间。在采摘下一个植株前,先计算一下t加上走到下一个植株、采摘、再回去所用的时间是否超出给定的时间。

  • 如果超出,那么现在就回去
  • 如果没超出,再采摘下一株

在这一过程中,统计采摘到的花生数。

从(x1, y1)到(x2, y2)的时间,为这两点间的曼哈顿距离,为 ∣ x 1 − x 2 ∣ + ∣ y 1 − y 2 ∣ |x1-x2|+|y1-y2| x1x2+y1y2

【题解代码】

解法1:使用数组填充,冒泡排序
#include <bits/stdc++.h>
using namespace std;
#define N 25
struct Node
{
    int x, y, n;//(x,y)有n个花生 
};
int main()
{
    Node a[405];
    int an = 0, m, n, k, t = 0, ans = 0;//t:用掉的时间 ans:采到的花生 
    cin >> m >> n >> k;
    for(int i = 1; i <= m; ++i)
        for(int j = 1; j <= n; ++j)
        {
            a[++an].x = i;
            a[an].y = j;
            cin >> a[an].n;
        }
    for(int i = 1; i <= an-1; ++i)//冒泡排序 根据花生数降序排序 
        for(int j = 1; j <= an-i; ++j)
            if(a[j].n < a[j+1].n)
                swap(a[j], a[j+1]);
    t = a[1].x + 1;//到第一株用的时间为第一株的行数,采一下用1单位的时间 
    if(t + a[1].x > k)//如果采第一株再回去的时间超过k,那么采不到 
    {
        cout << 0;
        return 0;
    } 
    ans += a[1].n;
    for(int i = 2; i <= an; ++i)
    {
        if(t + abs(a[i].x-a[i-1].x) + abs(a[i].y-a[i-1].y) + 1 + a[i].x > k)//如果从a[i-1]到a[i]再回路边的时间超过k
            break;//不采了,回路边
        else
        {
            t += abs(a[i].x-a[i-1].x) + abs(a[i].y-a[i-1].y) + 1;//到a[i]位置,采一株 
            ans += a[i].n;
        }
    }
    cout << ans;
    return 0;
}
解法2:使用STL
#include <bits/stdc++.h>
using namespace std;
#define N 25
struct Node
{
    int x, y, n;//(x,y)有n个花生 
    Node(){}
    Node(int a, int b, int c):x(a), y(b), n(c){}
    bool operator < (const Node &b) const//重载小于号,定义比较规则 
    {
        return n > b.n;//依照花生数降序排列 
    }
};
int dis(Node a, Node b)//求a、b两个位置间的曼哈顿距离 
{
    return abs(a.x-b.x) + abs(a.y-b.y);
}
int main()
{
    vector<Node> vec;
    int a, m, n, k, t = 0, ans = 0;//t:用掉的时间 ans:采到的花生 
    cin >> m >> n >> k;
    for(int i = 1; i <= m; ++i)
        for(int j = 1; j <= n; ++j)
        {
            cin >> a;
            vec.push_back(Node(i, j, a));
        }
    sort(vec.begin(), vec.end());//依照花生数降序排序 
    t = vec[0].x + 1;//到第一株用的时间为第一株的行数,采一下用1单位的时间 
    if(t + vec[0].x > k)//如果采第一株再回去的时间超过k,那么采不到 
    {
        cout << 0;
        return 0;
    } 
    ans += vec[0].n;
    for(int i = 1; i < vec.size(); ++i)
    {
        if(t + dis(vec[i], vec[i-1]) + 1 + vec[i].x > k)//如果从vec[i-1]到vec[i]再回路边的时间超过k
            break;//不采了,回路边
        else
        {
            t += dis(vec[i], vec[i-1]) + 1;//到vec[i]位置,采一株 
            ans += vec[i].n;
        }
    }
    cout << ans;
    return 0;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值