zoukankan      html  css  js  c++  java
  • CF998B Cutting 题解 DP+贪心

    题目链接:http://codeforces.com/problemset/problem/998/B

    题目描述

    有很多东西是可以被切割的,比如——树、纸张或者绳子。在这道题目里面你需要切割一个整数序列。
    现在告诉你一个整数序列,在这个整数序列里面有一些数,它们可能是奇数,也可能是偶数。
    给你一个固定的预算(因为切割是有成本的),你需要尽可能多地将这个整数序列切分成一系列连续子序列,
    使得每一个连续子序列中的 奇数元素的个数 和 偶数元素的个数 相同。
    比如,给你一个整数序列 [4,1,2,3,4,5,4,4,5,5] ,你可以将其切割两次变成
    [4,1 | 2,3,4,5 | 4,4,5,5] 。其中,[4,1] 、 [2,3,4,5] 以及 [4,4,5,5] 这三个连续子序列中包含的奇数个数等于偶数个数。
    如果你要将第 i 个元素和第 i+1 个元素之间切一刀,我们假设第 i 个元素对应的数值为 x ,第 j 个元素对应的数值为 y ,那么你需要消耗 |x-y| 个比特币。
    (|x-y| 表示 x-y 的差的绝对值)。
    而你的预算只有 B 个比特币,所以你需要计算一下在最多消耗 B 个比特币的情况下,你最多可以切几次。

    输入格式

    输入的第一行包含两个整数 n (2<=n<=100)和 B(1<=B<=100),分别表示整数序列中元素的个数和你最多可用的比特币的数量。
    输入的第二行包含 n 个整数,用于表示整数序列中的元素:a1,a2,……,an(1<=ai<=100)。

    输出格式

    输出一个整数,用于表示在最多消耗 B 个比特币的情况下,你最多可以切几刀,使得每一个切出来的连续子序列中包含相同的奇偶元素。

    样例输入1

    6 4
    1 2 5 10 15 20
    

    样例输出1

    1
    

    样例输入2

    4 10
    1 3 2 4
    

    样例输出2

    0
    

    样例输入3

    6 100
    1 2 3 4 5 6
    

    样例输出3

    2
    

    样例解释

    对于样例1,我们可以在 2 和 5 之间切割一刀,消耗 3 个比特币;
    对于样例2,我们无法切割;
    对于样例3,我们可以在 2 和 3 之间 以及 4 和 5 之间切割一刀,消耗 1+1=2 个比特币。

    问题分析

    这道题目涉及的算法是“DP”+“贪心”,可以用 dp+sort 或者 dp+heap 来做。
    首先我们假设 n 个元素的坐标从 1 到 n ,他们分别对应 a[1] 到 a[n] 。
    然后我们开一个输出 cc[] ,cc[i] 用于表示从 a[1] 到 a[i] 这 i 个数中奇数个数减去偶数个数之差。
    那么对于 1 到 n-1 范围内的 i ,如果 cc[i] == 0 ,那么它这个位置就是可以切割的,切割的成本是 abs(a[i+1]-a[i]) 。

    dp+sort解法:

    我们将 1 到 n-1 范围内的所有满足 cc[i]==0 条件的 i 对应的 abs(a[i+1]-a[i]) 放入一个数组中,然后将这个数组从小到大排序,每次取出一个数计数器cnt++,同时B减去这个数,直到B不够用为止;

    dp+heap(堆)解法:

    我们首先构造一个最小堆(可以用 priority_queue 模拟),然后将 1 到 n-1 范围内的所有满足 cc[i]==0 条件的 i 对应的 abs(a[i+1]-a[i]) 放入最小堆中1,然后每次从最小堆中取出堆顶元素,计数器cnt++,同时B减去这个数,直到B不够用为止。

    1、下面的代码演示了 dp+sort 的操作:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 110;
    
    int n, B, cnt, a[maxn], cc[maxn];
    vector<int> vec;
    
    int main() {
        cin >> n >> B;
        for (int i = 1; i <= n; i ++) {
            cin >> a[i];
            cc[i] = cc[i-1] + (a[i] % 2 ? 1 : -1);
        }
        for (int i = 1; i < n; i ++) if (!cc[i]) vec.push_back(abs(a[i+1]-a[i]));
        sort(vec.begin(), vec.end());
        for (vector<int>::iterator it = vec.begin(); it != vec.end(); it ++) {
            if (*it > B) break;
            B -= *it;
            cnt ++;
        }
        cout << cnt << endl;
        return 0;
    }
    

    2、下面的代码演示了 dp+heap 的操作:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 110;
    
    int n, B, cnt, a[maxn], cc[maxn];
    priority_queue<int, vector<int>, greater<int> > que;
    
    int main() {
        cin >> n >> B;
        for (int i = 1; i <= n; i ++) {
            cin >> a[i];
            cc[i] = cc[i-1] + (a[i] % 2 ? 1 : -1);
        }
        for (int i = 1; i < n; i ++) if (!cc[i]) que.push(abs(a[i+1]-a[i]));
        while (!que.empty()) {
            int u = que.top();
            que.pop();
            if (u > B) break;
            B -= u;
            cnt ++;
        }
        cout << cnt << endl;
        return 0;
    }
    
  • 相关阅读:
    tensorflow1.0 矩阵相乘
    tensorflow1.0 变量加法
    python 给字典按值排序,同样适合于其他
    pytorch 孪生神经网络DNN
    python 利用numpy同时打乱列表的顺序,同时打乱数据和标签的顺序
    python os模块获取指定目录下的文件列表
    创建自定义ssl证书用于https
    使用Maven命令行下载依赖库
    JAVA入门各种API参考
    在centos 6.9 x64下安装code::blocks步骤
  • 原文地址:https://www.cnblogs.com/quanjun/p/12191361.html
Copyright © 2011-2022 走看看