当前位置:   article > 正文

PAT甲级题目翻译+答案 AcWing(贪心)

PAT甲级题目翻译+答案 AcWing(贪心)

1033 To Fill or Not to Fill (25 分)

题意 :

  • 坐标轴上有n个加油站,给出每个加油站的位置和油价格,给出总路程长度和油箱最大容量,以及每升油平均跑多少路,最开始油箱是空的
  • 如果到不了终点,输出最多能到达多少路程;如果能到达终点,输出最低价格

思路 :

  • 按照坐标给每个加油站排序,记得加上终点
  • 如果第一个加油站不在起始点,return
  • 对于当前的加油站,要找到它 范围内(油箱满) 中第一个比当前便宜的;如果没有,就找范围内相对最便宜的;如果也没有,说明无法到达终点。可以统一为寻找变量k,出来后再分类
  • 记录当前油量

语法 :

  • for (int i = 0; i < n;)
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 510;

int c_max, d, d_avg, n;
struct Stop
{
    double p, d;
    
    bool operator< (const Stop& t) const
    {
        if (d != t.d) return d < t.d;
        return p < t.p;
    }
}s[N];

int main()
{
    scanf("%d%d%d%d", &c_max, &d, &d_avg, &n);
    
    for (int i = 0; i < n; i ++ ) scanf("%lf%lf", &s[i].p, &s[i].d);
    s[n] = {0, (double)d};
    
    sort(s, s + n + 1);
    
    if (s[0].d)
    {
        puts("The maximum travel distance = 0.00");
        return 0;
    }
    
    double res = 0, oil = 0;
    for (int i = 0; i < n;)
    {
        int k = -1;
        for (int j = i + 1; j <= n && s[j].d - s[i].d <= c_max * d_avg; j ++ )
        {
            if (s[j].p <= s[i].p)
            {
                k = j;
                break;
            }
            else if (k == -1 || s[k].p > s[j].p)
                k = j;
        }
        
        if (k == -1)
        {
            printf("The maximum travel distance = %.2lf\n", s[i].d + (double)c_max * d_avg);
            return 0;
        }
        
        if (s[k].p <= s[i].p)
        {
            res += ((s[k].d - s[i].d) / d_avg - oil) * s[i].p;
            oil = 0;
            i = k;
        }
        else
        {
            res += (c_max - oil) * s[i].p;
            oil = c_max - (s[k].d - s[i].d) / d_avg;
            i = k;
        }
    }
    
    printf("%.2lf\n", res);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71

1037 Magic Coupon (25 分)

题意 :

  • 给两个序列,每个序列中每个数只能被使用一次(可以不使用),求每次从两个序列中分别挑出一个数相乘之和最大值

思路 :

  • 双指针,不需要四个容器,只需要两个容器即可
  • for循环是满足条件才会进入到循环内
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1e5 + 10;

typedef long long ll;

int n, m;
ll a[N], b[N];

int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n && scanf("%lld", &a[i]); i ++ );
    scanf("%d", &m);
    for (int i = 0; i < m && scanf("%lld", &b[i]); i ++ );
    
    sort(a, a + n);
    sort(b, b + m);
    
    ll sum = 0;
    for (int i = 0, j = 0; i < n && j < m && a[i] < 0 && b[j] < 0; i ++ , j ++ ) sum += a[i] * b[j];
    for (int i = n - 1, j = m - 1; i >= 0 && j >= 0 && a[i] > 0 && b[j] > 0; i -- , j -- ) sum += a[i] * b[j];
    
    printf("%lld\n", sum);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

1067 Sort with Swap(0, i) (25 分)

题意 :

  • 给一个0-(n-1)的序列,每次可以将数字0与其他任意数交换,求最少交换次数使得达到升序效果

思路 :

  • 先转换成图论问题,0的位置在1,所以从0向1连一条边,1的位置在3,所以1向3连一条边,3的位置在4,4的位置在0,2的位置在2自己和自己连一条边,即,如果i在p[i]位置上,就i向p[i]连一条边,这样就可以转化成一个图论问题,且每一个数只会在一个位置上,只会有一个出边,且每个位置上只会有一个数,所以每个点只会有一个入边,即,每个点只会有一个出边和入边,也就是说每个点的出度和入度都是1,这样的图是很特殊的,必然是一堆环,每个点必然在环中;我们的目标就是让0在0位置,1在1位置,即让这堆环变成n个自环;
  • 现在看每个操作的效果,每次交换的数必然和0在同一个环或者不在同一个环,如果在同一个环内部,比如把0和5交换,0在3的位置上,5在7的位置上,那么0就在7的位置上,5就在3的位置上,发现,如果把0和环内的一个点交换,这个环就会破裂成两个环;如果把0和3交换,那么就是3指向0的指针,也就是3自环,0指向5,这样就是变成一个自环和另一个环;
  • 如果把0和另外一个环交换,比如0和8交换,就会形成一个更大的环;即,如果把0和另外一个环内交换,就是把两个环合并;如果0和环内的交换,就会把这个环破开
  • 总结,一共有两种操作,和环内与和环外;显然,环外点必然在某个时刻和0交换;和环内点交换的操作也可以分为两种,一个是与0的下一个点交换,会把下一个点变成自环,第二种是与非下一个点交换,会把环破成两个环,会发现这样的话,如果想变成自环,早晚还是要合并回来,所以可以发现,环内的第二种操作必然是不做的;即,对于环内的点,必然只与0的下一个点交换

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 输入时,记录每个值的位置,直到每个点都自环前,将0所在环所有点都自环,直到p[0]==0也就是0也自环,这个环就全部自环了,找到第一个没有自环的点,如果能找到,将0与这个点交换,合并环
  • 时间复杂度 O ( N ) O(N) O(N)
#include <iostream>
using namespace std;

const int N = 1e5 + 10;

int p[N];

int main()
{
    int n; scanf("%d", &n);
    
    int id;
    for (int i = 0; i < n; i ++ )
    {
        scanf("%d", &id);
        p[id] = i;
    }
    
    int res = 0;
    for (int i = 0; i < n; )
    {
        while (p[0]) swap(p[0], p[p[0]]), res ++ ;
        while (i < n && p[i] == i) i ++ ;
        if (i < n) swap(p[0], p[i]), res ++ ;
    }
    
    printf("%d", res);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

1125 Chain the Ropes (25 分)

题意 :

  • 每次串连后,原来两段绳子的长度就会减半。
  • 给定 N 段绳子的长度,你需要找出它们能串成的绳子的最大长度。

思路 :

  • 贪心从小到大选即可

语法 :

  • 由于每次都是现有的一段加上一个新的一段除以2,所以每次改变a[0]即可
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1e4 + 10;

double a[N];

int main()
{
    int n; scanf("%d", &n);
    for (int i = 0; i < n && scanf("%lf", &a[i]); i ++ );
    
    sort(a, a + n);
    
    for (int i = 1; i < n; i ++ ) a[0] = (a[0] + a[i]) / 2;
    
    printf("%d", (int)a[0]);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/627461
推荐阅读
相关标签
  

闽ICP备14008679号