6 ACwing 276 i-country 题解

i-country

题面

给定一个 \(n\times m\) 的矩阵,每个点上有一个权值,要求寻找一个包含 \(K\) 个点的凸连通块(连通块中间没有空缺,并且轮廓是凸的),使得连通块中格子的权值和最大

注意:凸连通块是指:连续的若干行,每行的左端点列号先递减、后递增,右端点列号先递增、后递减。(递增、递减都是非严格的)

求出这个最大的权值和,并给出连通块的具体方案,输出任意一种方案即可。

题解

我们依次考虑每一行如何选择格子

需要关注的地方

  • 当前处理到哪一行
  • 当前用了多少格子
  • 当前行的左端点、右端点
  • 左边、右边分别是伸长还是缩减

行数和选择的格子可以作为 dp 的阶段,这两个阶段都满足线性增长的特点,所以设 \(f(i,j,l,r,x,y)\) 表示考虑前 \(i\) 行,选了 \(j\) 个格子,第 \(i\) 行的左右端点为 \(l,r\) ,左边右边的伸长/缩短状态为 \(x/y\)

状态转移,注意到,缩短可以从伸长转移过来,但伸长不可以从缩短转移过来。最终的目标状态是这四种状态中的任意一种,我卡了很长时间

  • \(f(i,j,l,r,0,0) \to max\{f(i-1,j-(r-l+1),l',r',0,0)\}\)
  • \(f(i,j,l,r,0,1)\to max\{f(i-1,j-(r-l+1),l',r',0,0/1) \}\)
  • \(f(i,j,l,r,1,0)\to max\{f(i-1,j-(r-l+1),l',r',0/1,0) \}\)
  • \(f(i,j,l,r,1,1)\to max\{f(i-1,j-(r-l+1),l',r',0/1,0/1) \}\)

code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>

using namespace std;

const int N = 20;

int n, m, k;
int f[N][N * N][N][N][2][2];
int a[N][N];

struct PRE {
    int i, j, l, r, s, t, val;
} Pre[N][N * N][N][N][2][2];

/*
f[i][j][l][r][0/1][0/1]
表示考虑前 i 行,选了 j 个格子,
第 i 行从 l 选到 r, 
左/右分别是 缩短/伸长 趋势
的最大价值
*/

int main () {

    cin >> n >> m >> k;
    for (int i = 1; i <= n; i ++) {
        for (int j = 1; j <= m; j ++) {
            cin >> a[i][j];
        }
    }

    //初始化 : 初始都为 0 即可,不会出现从不合法状态转移

    for (int i = 1; i <= n; i ++) {

        /* 
        不选
        其实不用,因为不可能前面选了一些,中间不选,后面再选一些
        for (int l = 1; l <= m; l ++) {
            for (int r = l; r <= m; r ++) {
                for (int x = 0; x <= 1; x ++) {
                    for (int y = 0; y <= 1; y ++) {
                        f[i][0][l][r][x][y] = f[i - 1][0][l][r][x][y];
                    }
                }
            }
        }
        */

        for (int j = 1; j <= k; j ++) {
            for (int l = 1; l <= m; l ++) {
                for (int r = l; r <= m; r ++) {

                    int len = r - l + 1;
                    if (len > j) continue;

                    //左伸长,右伸长
                    {   
                        auto &now = f[i][j][l][r][1][1];
                        auto &pre = Pre[i][j][l][r][1][1];
                        for (int p = l; p <= r; p ++) {
                            for (int q = p; q <= r; q ++) {
                                auto val = f[i - 1][j - len][p][q][1][1];
                                if (now < val) {
                                    now = val;
                                    pre = {i - 1, j - len, p, q, 1, 1, 0};
                                }
                            }
                        }
                        for (int k = l; k <= r; k ++) {
                            now += a[i][k];
                        }
                    }

                    //左伸长,右缩短
                    {
                        auto &now = f[i][j][l][r][1][0];
                        auto &pre = Pre[i][j][l][r][1][0];
                        for (int p = l; p <= r; p ++) {
                            for (int q = r; q <= m; q ++) {
                                for (int y = 0; y <= 1; y ++) {
                                    auto val = f[i - 1][j - len][p][q][1][y];
                                    if (now < val) {
                                        now = val;
                                        pre = {i - 1, j - len, p, q, 1, y, 0};
                                    }
                                }
                            }
                        }
                        for (int u = l; u <= r; u ++) {
                            now += a[i][u];
                        }
                    }

                    //左缩短,右伸长
                    {
                        auto &now = f[i][j][l][r][0][1];
                        auto &pre = Pre[i][j][l][r][0][1];
                        for (int p = 1; p <= l; p ++) {
                            for (int q = l; q <= r; q ++) {
                                for (int x = 0; x <= 1; x ++) {
                                    auto val = f[i - 1][j - len][p][q][x][1];
                                    if (now < val) {
                                        now = val;
                                        pre = {i - 1, j - len, p, q, x, 1, 0};
                                    }
                                }
                            }
                        }
                        for (int u = l; u <= r; u ++) {
                            now += a[i][u];
                        }
                    }

                    //左缩短,右缩短
                    {
                        auto &now = f[i][j][l][r][0][0];
                        auto &pre = Pre[i][j][l][r][0][0];
                        for (int p = 1; p <= l; p ++) {
                            for (int q = r; q <= m; q ++) {
                                for (int x = 0; x <= 1; x ++) {
                                    for (int y = 0; y <= 1; y ++) {
                                        auto val = f[i - 1][j - len][p][q][x][y];
                                        if (now < val) {
                                            now = val;
                                            pre = {i - 1, j - len, p, q, x, y, 0};
                                        }
                                    }
                                    
                                }
                            }
                        }
                        for (int u = l; u <= r; u ++) {
                            now += a[i][u];
                        }
                    }

                }
            }
        }
    }

    PRE ans = {0, 0, 0, 0, 0, 0, 0};
    for (int i = 1; i <= n; i++) {
        for (int l = 1; l <= m; l ++) {
            for (int r = 1; r <= m; r ++) {
                for (int x = 0; x <= 1; x ++) {
                    for (int y = 0; y <= 1; y ++) {
                        if (ans.val < f[i][k][l][r][x][y]) {
                            ans = {i, k, l, r, x, y, f[i][k][l][r][x][y]};
                        }
                    }
                }
            }
        }
    }

    printf ("Oil : %d\n", ans.val);
    
    while (ans.i != 0 && ans.j != 0) {
        for (int j = ans.l; j <= ans.r; j ++) {
            printf ("%d %d\n", ans.i, j);
        }
        ans = Pre[ans.i][ans.j][ans.l][ans.r][ans.s][ans.t];
    }
    
    return 0;
}
posted @ 2025-10-05 17:59  michaele  阅读(12)  评论(0)    收藏  举报