「luogu3974」[TJOI2015] 组合数问题

「luogu3974」[TJOI2015] 组合数问题

题目链接

\(Description\)

给一个 \(n \times m \ (1 \leq n, m \leq 10^3)\) 的网格图,每个格子中有好多块财宝;
每次从左上角出发,只能往右或下走了,每一次经过一个格子至多只能捡走一块财宝;
问至少要走几次才可能把财宝全捡完。

\(Solution\)

把每一个财宝拆成一个点,就是求 \(DAG\) 最小不相交路径覆盖;
根据 \(Dilworth\) 定理:最小不相交路径覆盖 = 最长反链;
题目转换为求一个从右上到左下,取出一个最大的任意两点不可达的点集。
\(f_{i, j}\) 表示以 \((i, j)\) 为左下角的矩形里的最长反链:

\[f_{i,j} = \max \big\{ f_{i - 1, j + 1} + a_{i,j}, \ \max \{ { f_{i - 1, j}, f_{i, j + 1} } \} \big\} \]

\(Source\)

#include <cstdio>
#include <cstring>
#include <algorithm>
int in() {
    int x = 0; char c = getchar(); bool f = 0;
    while (c < '0' || c > '9')
        f |= c == '-', c = getchar();
    while (c >= '0' && c <= '9')
        x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    return f ? -x : x;
}
template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; }
template<typename T>inline void chk_max(T &_, T __) { _ = _ > __ ? _ : __; }

const int N = 1e3 + 5;

int n, m, mp[N][N];
long long f[N][N];

int main() {
    //freopen("in", "r", stdin);
    int tim = in();
    while (tim--) {
        n = in(), m = in();
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++j)
                mp[i][j] = in();
        for (int i = 1; i <= n; ++i)
            for (int j = m; j; --j) {
                f[i][j] = f[i - 1][j + 1] + mp[i][j];
                chk_max(f[i][j], f[i][j + 1]);
                chk_max(f[i][j], f[i - 1][j]);
            }
        printf("%lld\n", f[n][1]);
    }
    return 0;
}
posted @ 2019-10-23 10:14  15owzLy1  阅读(...)  评论(...编辑  收藏