zoukankan      html  css  js  c++  java
  • 蓝桥训练之动态规划

    入门

    数组分组

    题意:

    一个数组可被分为n组,整个数组的权值被定义为各组内数字之积对1000取模后的总和,求数组的最大权值

    思路:

    我们用dp[i]表示前i个数分组的最大权值,对于位置i,我们可以枚举最后一个分组的起始位置为j,计算i,j之间的权值,然后更新dp[i]即可。

    为了避免过多的计算,我们需要预处理出来每个区间的乘积对1000取模的结果。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int maxn = 1e3+100, mod = 1000;
    int n, a[maxn], dp[maxn], pre[maxn][maxn];
    int main(){
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for(int i = 1; i <= n; i++){
            pre[i][i] = a[i];
            for(int j = i+1; j <= n; j++)
                pre[i][j] = (pre[i][j-1]*a[j])%mod;
        }
        dp[1] = a[1];
        for(int i = 2; i <= n; i++){
            for(int j = 0; j < i ; j++)
                dp[i] = max(dp[i], dp[j]+pre[j+1][i]);
        }
        printf("%d", dp[n]);
    }
    View Code

    墙壁涂色

    题意:

    一个环形的房间被分成n块,每块的颜色可以为R、G、B,但是相邻两快的颜色必须不同,求涂色的方案数

    思路:

    这是道递推的题目,用dp[i]表示长度为i的方案数

    递推的本质:用已知推未知,寻找前后项之间的关系。仔细观察发现可以分为两种情况,当第1项和第n-1项不同色时,第n项只能取一种颜色;当两者取相同颜色时,第n项可以取两种颜色,于是得到递推表达式:dp[n] = dp[n-1] + 2*dp[n-2]

    最后注意初始化的时候需要初始化dp[0]、dp[1]、dp[2](原因稍加思考便知),并且输出使用long long否则溢出

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define ll long long
    using namespace std;
    const int maxn = 1e5+100;
    ll n, a[maxn], dp[maxn];
    int main(){
        scanf("%lld", &n);
        dp[1] = 3, dp[2] = 6, dp[3] = 6;
        for(int i = 4; i <= n; i++)
            dp[i] = dp[i-1] + 2*dp[i-2];
        printf("%lld", dp[n]);
    }
    View Code

    过河 [POJ 1700. Crossing River]

    题意:

    有n个人准备过河,他们只有一只船,这只船每次只能通过坐不超过2人,每个人都有不同的划船速度;同一组过河的人的速度是由较慢的速度来确定。你的任务是确定一个策略,最大限度的减少他们过河的时间(使他们最快的过河)

    思路:

    我们先看下样例,四个人过桥花费的时间分别为 1 2 5 10,具体步骤是这样的:

    第一步:1和2过去,花费时间2,然后1回来(花费时间1)
    第二歩:3和4过去,花费时间10,然后2回来(花费时间2)
    第三歩:1和2过去,花费时间2,总耗时17

    这道题目更像是道贪心的题目,拿到题目后可以用数学归纳法求最短花费时间,可以发现可以有两种贪心策略:

    1.考虑划船快的人划的次数最多 [最快的人依次把最慢的两个人渡过河再回来]

    2.考虑划的慢的人尽量少占用划的快的人的时间. [最快的两个人先过河,最快的人回来,然后最慢的两个过河,第二快的回来。直到剩余人数少于4人为止]

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int maxn = 1e3+100;
    int a[maxn];
    int cal(int n) {
        int ans = 0;
        while (n >= 4) {
            // 最快的人把最慢的两个人渡过河消耗的时间
            int s1 = a[n] + a[n - 1] + a[1] * 2;
            // 最快的两个人把最慢的两个人渡过河消耗的时间
            int s2 = a[2] * 2 + a[1] + a[n];
            ans += min(s1, s2);
            // 一次渡河之后不管选哪种渡河方式,最快的两个人都要回来
            n -= 2;
        }
        if (n==2) return ans + a[2];
        for(int i = 1; i <= n; i++) ans += a[i];
        return ans;
    }
    int main() {
        int t, n;
        scanf("%d", &t);
        while (t--) {
            scanf("%d", &n);
            for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
            sort(a+1, a+1+n);
            printf("%d
    ", cal(n));
        }
        return 0;
    }
    View Code

     Reference:

    https://www.cnblogs.com/xiaoyezi-wink/p/11183637.html

    https://blog.nowcoder.net/n/2467bddb99424462b1ce2f7f26d5f31a

    https://www.git2get.com/av/38084571.html

    最大子段和

    蒜头君的最大子段和

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define inf 1e12
    #define ll long long
    using namespace std;
    const int maxn = 1e6+100;
    ll n, a[maxn], dp[maxn], ans = -inf;
    int main(){
        scanf("%lld", &n);
        for(int i = 1; i <= n; i++){
            scanf("%lld", &a[i]);
            dp[i] = max(a[i], dp[i-1]+a[i]);
            ans = max(ans, dp[i]);
        }
        printf("%lld", ans);
    } 
    View Code

    蒜头君的最大子矩阵和

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define inf 0x3f3f3f3f
    #define ll long long
    using namespace std;
    const int maxn = 1e3+100;
    ll n, m, tmp;
    ll sum[maxn][maxn], dp[maxn], ans = -inf;
    int main(){
        scanf("%lld %lld", &n, &m);
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                scanf("%lld", &tmp);
                sum[i][j] = sum[i-1][j]+tmp;
            }
        }
        for(int i = 1; i <= n; i++){
            for(int k = 0; k < i; k++){
                for(int j = 1; j <= m; j++){
                    dp[j] = max(dp[j-1], 0ll) + sum[i][j]-sum[k][j];
                    ans = max(ans, dp[j]);
                }
            }
        }
        printf("%lld", ans);
    } 
    View Code

    最长公共子序列

    最长公共子序列

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define inf 0x3f3f3f3f
    #define ll long long
    using namespace std;
    const int maxn = 1e3+100;
    char a[maxn], b[maxn];
    int dp[maxn][maxn];
    int main(){
        scanf("%s%s", a+1, b+1);
        int n = strlen(a+1), m = strlen(b+1);
        for(int i =  1; i <= n ;i++){
            for(int j = 1; j <= m; j++){
                dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
                if(a[i]==b[j]) dp[i][j] = max(dp[i][j], dp[i-1][j-1]+1);
            }
        }
        printf("%d", dp[n][m]);
    }
    View Code

    编辑距离

    回文串

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define inf 0x3f3f3f3f
    #define ll long long
    using namespace std;
    const int maxn = 3e3+100;
    char s[maxn];
    int dp[maxn][maxn];
    int main(){
        scanf("%s", s+1);
        int n = strlen(s+1);
        for(int i = n-1; i >= 1; i--){
            for(int j = i+1; j <= n; j++){
                if(s[i]==s[j]) dp[i][j] = dp[i+1][j-1];
                else dp[i][j] = min(dp[i+1][j], dp[i][j-1]) + 1;
            }
        }    
        printf("%d", dp[1][n]);
    }
    Origin
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define inf 0x3f3f3f3f
    #define ll long long
    using namespace std;
    const int maxn = 1e4+100;
    char s[maxn];
    int dp[maxn];
    int main(){
        scanf("%s", s+1);
        int n = strlen(s+1);
        for(int i = n-1; i >= 1; i--){
            int pre = 0;
            for(int j = i+1; j <= n; j++){
                int tmp = dp[j];
                if(s[i]==s[j]) dp[j] = pre;
                else dp[j] = min(dp[j], dp[j-1]) + 1;
                pre = tmp;
            }
        }    
        printf("%d", dp[n]);
    }
    状态压缩
  • 相关阅读:
    Mysql 备份 导入导出
    简 历
    Mysql 表结构 创建 限制 关联
    Unity 碰撞检测
    Unity 获取键值
    关于大型网站系统的一些问题
    关于zookeeper
    dubbo分布式和消息队列
    集群
    cookie及安全问题
  • 原文地址:https://www.cnblogs.com/wizarderror/p/14641429.html
Copyright © 2011-2022 走看看