• 【题解】ZJOI2013蚂蚁寻路


      这题强呀……打了10+30暴力之后苦想1h并不会做……于是去看题解。看题解的时候又莫名各种看错,结果看了好久才懂……记录一下血泪史吧。

      这题不难发现走出来的图形就是一个高低高低的城堡型图案,命名为高峰跟低谷的话就是一共有k个低谷和k + 1个高峰,且交替出现。发现其实这个图形是由2 * k + 1个矩形所构成的,我们考虑将这样许多矩形看做转移的方向:f[i][j][p][h]代表以点(i, j)为左下角,当前枚举到的是第p个矩形,且高度为(i - h + 1)所能获得的最大权值。

      转移方程:

        (f[i][j][p][h] = left { f[i][j - 1][p][h], f[i][j - 1][p][h']] ight } + s[j][i] - s[j][h - 1]; )

      其中第一部分代表和j - 1处于同一个矩形当中,第二部分则表示根据p的奇偶性选择<h或>h的转移。第二部分如果枚举,则复杂度太高了难以承受,所以用另一个数组g来保存,追加一维0/1来表示是>还是<中的最大值。然后发现其实 i 这一维是没有参与转移的,所以将这一维去掉,节约空间。期间有一个让我比较纠结的地方,就是

        ( ans = max(f[i][j][k][i], g[i][j][k][i][0]); )

      起初并没有很理解为什么要将前一部分考虑进来。当高度等于i,不是说明这是一个低谷吗?为什么会符合条件呢?但其实有一种情况下是可以的:当没有低谷的时候,这样是一个符合条件的解。追加辅助数组的dp做的太少了,要多多加油呀ヾ(๑╹◡╹)ノ"

    #include <bits/stdc++.h>
    using namespace std;
    #define INF 999999999
    #define maxn 105
    int n, m, k, ans = -INF, sum[maxn][maxn];
    int f[maxn][maxn][maxn], g[maxn][maxn][maxn][2];
    
    int read()
    {
        int x = 0, k = 1;
        char c;
        c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
     
    void work()
    {
        for(int p = 1; p <= k; p ++)
            for(int h = 1; h <= n; h ++)
            {
                f[0][p][h] = -INF;
                g[0][p][h][0] = g[0][p][h][1] = -INF;
            }
            
        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= m; j ++)
            {
                for(int p = 1; p <= k; p ++)
                {
                    for(int h = 1; h <= i; h ++)
                    {
                        f[j][p][h] = max(f[j - 1][p][h], g[j - 1][p - 1][h][p % 2]);
                        f[j][p][h] += sum[j][i] - sum[j][h - 1];
                    }
                    g[j][p][1][0] = -INF;
                    for(int h = 2; h <= i; h ++)
                        g[j][p][h][0] = max(g[j][p][h - 1][0], f[j][p][h - 1]);
                    g[j][p][i][1] = -INF;
                    for(int h = i - 1; h >= 1; h --)
                        g[j][p][h][1] = max(g[j][p][h + 1][1], f[j][p][h + 1]);
                }
                ans = max(ans, max(f[j][k][i], g[j][k][i][0]));
            }
    }
    
    int main()
    {
        n = read(), m = read(), k = read();
        k = k * 2 + 1;
        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= m; j ++)
            {
                int t = read();
                sum[j][i] += sum[j][i - 1] + t;
            }
        work();
        printf("%d
    ", ans);
        return 0;
    }
  • 相关阅读:
    SpringBoot 动态修改定时任务频率
    window三种程序自启动方式
    vbs与bat脚本实现本地jdk版本自动切换
    java连接sqlserver数据库
    java连接Access数据库
    Java如何连接Access数据库(两种方式实例代码)
    java连接access数据库的三种方式以及远程连接
    Linux下实现MySQL数据库每天定时自动备份
    解决谷歌浏览器http链接自动跳转到https的问题
    2021年第一天
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/8977424.html
Copyright © 2020-2023  润新知