• 入门算法题——动态规划篇(一)


    转载请注明出处:http://www.cnblogs.com/xianyue

    题1:教师的困惑

    题目描述

    高考结束了,高三(一)班的王老师又即将要送走他的这一届的学生。为了给学生们留个念想,她决定去商店里为每一个学生买一个礼物。王老师班里一共有n个学生,商店里一共有m件礼物,每一件礼物都有各自的价格。王老师需要从这m件礼物里面购买n件,但是她买之前发现一个问题:如果给A同学买的礼物比B同学贵,B同学很可能就会觉得不公平。为了尽量避免这种情况的出现,王老师希望购买的n件礼物中最贵的哪一件的价格和最便宜的那一件的价格之差最小。请你帮王老师计算一下从m件礼物中购买n件使得最贵礼物和最便宜礼物地价格差最小对应地最小的价格差。

    输入

    第一行两个正整数n和m(2<=n<=m<=50)。
    第二行m个正整数表示m件礼物的价格。

    输出

    输出从m件礼物中购买n件使得最贵礼物和最便宜礼物地价格差最小对应地最小的价格差。

    样例输入

    4 6
    10 12 10 7 5 22

    样例输出

    5

    题解

    这道题我们需要先将m个数排序,然后从n-1到m-1遍历i,答案是a[i]-a[i-n+1]中地最小值。

    代码

    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define inf (1<<29)
    int n, m, f = inf, a[55];
    int main()
    {
        cin >> n >> m;
        for (int i = 0; i < m; i ++)
            cin >> a[i];
        sort(a, a+m);
        for (int i = n-1; i < m; i ++)
            f = min(f, a[i]-a[i-n+1]);
        cout << f << endl;
        return 0;
    }
    

    题2:取数字1

    题意

    给你一个长度为n地数组a,你每次可以从其中取一个数a[k],当你取完a[k]之后,a[k-1]和a[k+1](如果有的话)便被锁定了(也就是说你取了a[k]之后便永远不能取a[k-1]和a[k+1]了),同时你将会获得a[k]地积分。求你最多能获得的积分。

    输入

    第一行一个数n。
    接下来一行n个正整数表示数组a。

    输出

    你所能获得的最大的积分。

    样例输入

    5
    5 3 5 3 4

    样例输出

    14

    题解

    这道题可以列状态转移方程:

    f[i] = a[i] + max(f[i-2], f[i-3])
    

    其中f[i]表示a[0]到a[i]这i+1个数并且我取了a[i]所获得的最大积分。

    代码

    #include <iostream>
    using namespace std;
    const int maxn = 100010;
    int n, a[maxn], f[maxn], res = 0;
    int main()
    {
        cin >> n;
        for (int i = 0; i < n; i ++)
            cin >> a[i];
        f[0] = a[0];
        f[1] = a[1];
        f[2] = a[0] + a[2];
        for (int i = 3; i < n; i ++)
        {
            f[i] = a[i] + max(f[i-2], f[i-3]);
        }
        for (int i = 0; i < n; i ++)
            res = max(res , f[i]);
        cout << res << endl;
        return 0;
    }
    

    题3:取数字2

    题意

    给你一个长度为n地数组a,你每次可以从其中取一个数a[k],当你取完a[k]之后,数组中所有值为a[k]-1或a[k]+1的数都会被删除,同时你将会获得a[k]地积分。求你最多能获得的积分。

    输入

    第一行一个数n。(1<=n<=100000)
    接下来一行n个正整数表示数组a。(1<=a[i]<=100000)

    输出

    你所能获得的最大的积分。

    样例输入

    5
    5 3 5 3 4

    样例输出

    16

    题解

    可以列出状态转移方程:

    f[i] = max(f[i-2], f[i-3]) + i * num[i];
    

    其中,num[i]为a[i]==i的数的个数。
    f[i]表示数值从0到i这个范围,且选择了所有数值为i的数,所能得到的总积分。

    代码

    #include <iostream>
    #include <map>
    using namespace std;
    map<int, int> num;
    const int maxn = 100010;
    int n, a[maxn];
    long long f[maxn];
    int main()
    {
        cin >> n;
        for (int i = 0; i < n; i ++)
        {
            cin >> a[i];
            num[ a[i] ] ++;
        }
        f[0] = 0;
        f[1] = 1 * num[1];
        f[2] = 2 * num[2];
        for (int i = 2; i <= 100000+3; i ++)
        {
            f[i] = max(f[i-2], f[i-3]) + (long long)i * (long long)num[i];
        }
        cout << f[100000+3] << endl;
        return 0;
    }
    

    题4:减丝带

    题目描述

    小丽和小梅剪丝带。
    已知四代的长度为n米,要求剪出来的四代的长度必须是a或b或c米。求:在满足条件的情况下它们最多能够剪出多少条四代。

    输入

    一行四个整数n,a,b,c。

    输出

    最多能够剪出的丝带的数目。

    样例输入

    7 5 5 2

    样例输出

    2

    题解

    这道题有点类似完全背包问题:
    只不过背包被要求要正好装满。
    所以一开始做了处理:除了f[0]以外的f[i]都置为一个无穷小的数。(关于f的计算见代码)

    代码

    #include <iostream>
    using namespace std;
    const int maxn = 4010;
    #define inf (1<<29)
    int n, a, f[maxn];
    int main()
    {
        cin >> n;
        for (int i = 1; i <= n; i ++)
            f[i] = -inf;
        for (int i = 0; i < 3; i ++)
        {
            cin >> a;
            for (int j = a; j <= n; j ++)
                f[j] = max(f[j], f[j-a]+1);
        }
        cout << f[n] << endl;
        return 0;
    }
    

    题5:翻转游戏

    题目大意

    有一个长度为n的数组a,a[i]为0或者1。你可以选择两个整数i和j(0<=i<=j<n),然后对数组a的从a[i]到a[j]的数进行一次翻转操作(即a[i]到a[j]的每一个数x都会变为1-x),求进行了一次反转操作后,数组a中n个数的和最大为多少?

    输入

    第一行包括一个数n。
    第二行n个数表示数组a。

    输出

    进行一次翻转操作后最大的可能总和。

    样例输入

    5
    1 0 0 1 0

    样例输出

    4

    题解

    根据数组a我们可以求得一个数组b。
    b[i]表示a[i]翻转后的获利。

    • 如果a[i]一开始为0,则翻转后变为1,获利1
    • 如果a[i]一开始为1,则翻转后变为0,获利-1

    据此,我们可以对数组b求一个最大连续子序列和,将该最大连续子序列和加上数组a的元素总和便为答案。

    代码

    #include <iostream>
    using namespace std;
    const int maxn = 110;
    int a[maxn], b[maxn], n, sum = 0, t;
    int main()
    {
        cin >> n;
        for (int i = 0; i < n; i ++)
        {
            cin >> a[i];
            b[i] = (a[i] ? -1 : 1);
            sum += a[i];
        }
        t = b[0];
        int c = t;
        for (int i = 1; i < n; i ++)
        {
            c = max(b[i], c + b[i]);
            if (c > t)
                t = c;
        }
        cout << sum + t << endl;
        return 0;
    }
    
  • 相关阅读:
    R语言 dbWriteTable 写入数据库 为空和乱码问题
    data.table进阶
    简述ODS,和数据仓库做简单的比较
    深入ff and ffbase
    R语言操作mysql上亿数据量(ff包ffbase包和ETLUtils包)
    基于mondrain 的原理纠正特殊指标值
    基于mondrian聚合表的R计算olap开发
    dplyr快速入门
    R中的data.table 快速上手入门
    删除pentaho用户和用户文件夹
  • 原文地址:https://www.cnblogs.com/xianyue/p/7137099.html
Copyright © 2020-2023  润新知