• 2004年NOIP普及组复赛题解


    题目涉及算法:

    • 不高兴的津津:入门题;
    • 花生采摘:贪心;
    • FBI树:递归、DP求区间和;
    • 火星人:模拟。

    不高兴的津津

    题目链接:
    简单枚举。
    遍历一遍,找到 (a[i] + b[i]) 最大的那个坐标即可。
    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    int a[8], b[8], id;
    int main() {
        for (int i = 1; i <= 7; i ++) {
            cin >> a[i] >> b[i];
            if (a[i] + b[i] > 8 && (!id || a[i]+b[i] > a[id]+b[id]))
                id = i;
        }
        cout << id << endl;
        return 0;
    }
    

    花生采摘

    题目链接:https://www.luogu.org/problem/P1086
    贪心。
    这里告诉我们一个条件是“假设这些植株下的花生个数各不相同”,所以我们可以直接按照花生个数从大到小进行排列,但是每一个元素同时需要记录他的行号、列号和花生个数。
    对于排好序的元素,从路边到第 (0) 棵植株(假设坐标从 (0) 开始)的时间是确定的,就是第 (0) 棵植株的行号,采摘好第 (n-1) 棵植株之后回到路边的时间也是可以确定的,就是 (1)
    而从第 (i) 棵植株到第 (i+1) 棵植株的时间有两种过渡方式:

    1. 从第 (i) 棵植株直接走到第 (i+1) 棵植株并采摘,花费的时间是 (|x_i-x_{i+1}| + |y_i+y_{i+1}| + 1) (这里,(x_i) 表示第 (i) 棵植株的行号,(y_i) 表示第 (i) 棵植株的列号, (|a|) 表示 (a) 的绝对值);
    2. 从第 (i) 棵植株跳回路边,然后再从路边走到第 (i+1) 棵植株,并采摘,花费的时间是 (x_i + x_{i+1} + 1)

    而我应该取两者的较小值。(Rightarrow) 这就是此题贪心的精髓。
    后来我发现我想多了,这个题目是假设猴子在取花生的过程中不会回到大路上的,有些同学在思考是否可能在中间回到大路上,因为题目没说在大路上移动要花时间,所以有可能中途出来再进去摘的花生更多。
    所以我们只考虑上述第2个条件就可以了~

    然后这里有一个限定时间 (K) ,我们只需要确定在限定时间内能够以上述方案摘多少株就可以了。

    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 440;
    struct Node {
        int x, y, z;
    } a[maxn];
    int n, m, k, cnt, dis, ans;
    bool cmp(Node a, Node b) {
        return a.z > b.z;
    }
    int main() {
        cin >> n >> m >> k;
        for (int i = 1; i <= n; i ++) {
            for (int j = 1; j <= m; j ++) {
                a[cnt].x = i;
                a[cnt].y = j;
                cin >> a[cnt].z;
                if (a[cnt].z) cnt ++;
            }
        }
        sort(a, a+cnt, cmp);
        for (int i = 0; i < cnt; i ++) {
            if (!i) dis += a[i].x + 1;
            // else dis += min( abs(a[i].x-a[i-1].x) + abs(a[i].y-a[i-1].y), a[i-1].x + a[i].x ) + 1;
            else dis += abs(a[i].x - a[i-1].x) + abs(a[i].y - a[i-1].y) + 1;
            if (dis + a[i].x <= k) ans += a[i].z;
        }
        cout << ans << endl;
        return 0;
    }
    

    FBI树

    题目链接:https://www.luogu.org/problem/P1087
    这道题目就是用递归实现区间遍历。
    我可以使用动态规划来实现区间和,然后递归,或者套线段树模板。
    这里仅介绍使用使用动态规划+递归实现,代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = (1<<10|1);
    char ch[maxn+10];
    int tree[maxn<<2], n, m, sum[maxn];
    void solve(int L, int R, int n) {
        if (n) {
            solve(L, L+(1<<(n-1))-1, n-1);
            solve(L+(1<<(n-1)), R, n-1);
        }
        int tmp = sum[R] - sum[L-1];
        if (tmp == (1<<n)) putchar('I');
        else if (!tmp) putchar('B');
        else putchar('F');
    }
    int main() {
        scanf("%d%s", &n, ch+1);
        m = (1<<n);
        for (int i = 1; i <= m; i ++)
            sum[i] = sum[i-1] + (ch[i] == '1');
        solve(1, m, n);
        return 0;
    }
    

    火星人

    题目链接:https://www.luogu.org/problem/P1088
    这道题目是一道模拟,模拟下一个全排列。
    但是STL提供了 next_permutation 函数,我就直接拿来用了。
    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 10010;
    int n, m, a[maxn];
    int main() {
        cin >> n >> m;
        for (int i = 0; i < n; i ++) cin >> a[i];
        while (m --) next_permutation(a, a+n);
        for (int i = 0; i < n; i ++) {
            if (i) putchar(' ');
            cout << a[i];
        }
        cout << endl;
        return 0;
    }
    

    作者:zifeiy

  • 相关阅读:
    java8 parallel并行处理实战
    java相关技术问答(二)
    [安卓基础] 007.管理Activity的生命周期
    [Python基础]009.os模块(1)
    [Objective-C] 012_数据持久化_XML属性列表,NSUserDefaults
    SD.Team团队人物形象
    读Pyqt4教程,带你入门Pyqt4 _013
    [Objective-C] 011_数据持久化_NSKeyedArchiver
    [Objective-C] 010_Foundation框架之NSSet与NSMutableSet
    [JavaWeb基础] 007.Struts2的配置和简单使用
  • 原文地址:https://www.cnblogs.com/codedecision/p/11717543.html
Copyright © 2020-2023  润新知