zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    将Nginx添加到windows服务中
    springboot使用redis管理session
    GIT常用命令
    阻止360、谷歌浏览器表单自动填充
    谈谈对Spring IOC的理解
    同一个Nginx服务器同一端口配置多个代理服务
    LeetCode 653. Two Sum IV
    109. Convert Sorted List to Binary Search Tree(根据有序链表构造平衡的二叉查找树)
    108. Convert Sorted Array to Binary Search Tree(从有序数组中构造平衡的BST)
    LeetCode 236. Lowest Common Ancestor of a Binary Tree(二叉树求两点LCA)
  • 原文地址:https://www.cnblogs.com/codedecision/p/11717543.html
Copyright © 2011-2022 走看看