P3974 [TJOI2015]组合数学

P3974 [TJOI2015]组合数学

题目描述

为了提高智商,ZJY开始学习组合数学。某一天她解决了这样一个问题:给一个网格图,其中某些格子有财宝。每次从左上角出发,只能往右或下走。问至少要走几次才可能把财宝全捡完。

但是她还不知足,想到了这个问题的一个变形:假设每个格子中有好多块财宝,而每一次经过一个格子至多只能捡走一块财宝,其他条件不变,至少要走几次才可能把财宝全捡完?

这次她不会做了,你能帮帮她吗?

输入输出格式

输入格式:

第一行为一个正整数t,表示数据组数

每组数据的第一行是两个正整数n和m,表示这个网格图有n行m列。

接下来n行,每行m个非负整数,表示这个格子中的财宝数量(0表示没有财宝)。

输出格式:

对于每组数据,输出一个整数,表示至少走的次数。

输入输出样例

输入样例#1: 
1
3 3
0 1 5
5 0 0
1 0 0
输出样例#1: 
10

数据范围

对于30%的数据,n≤5.m≤5,每个格子中的财宝数不超过5块。

对于50%的数据,n≤100,m≤100,每个格子中的财宝数不超过1000块

对于100%的数据,n≤1000,m≤1000,每个格子中的财宝不超过10^6块

————————————————————————————————————————————————————————

首先DZY tql!OTZ

Dilworth定理:对于一个偏序集,最少链划分等于最长反链长度。

Dilworth定理的对偶定理:对于一个偏序集,其最少反链划分数等于其最长链的长度。

推论:DAG的最小链覆盖=最大点独立集

显然题目要求求出最小链覆盖

由于题目限制只能向右/下走,所以题目中的最大点独立集一定是任意两点都满足左下和右上的对应关系,两两不可到达。

dp搞一下

code

#include<iostream>
int T, n, m, a[1010][1010], f[1010][1010];
int main() {
    std::cin >> T;
    while(T -- ){
        std::cin >> n >> m;
        for (int i = 1; i <= n; ++ i)
            for (int j = 1;j <= m; ++ j)
                std::cin >> a[i][j];
        for (int i = 1; i <= n; ++ i)
            for (int j = m; j ; -- j)
                f[i][j] = std::max(f[i - 1][j + 1] + a[i][j],
                            std::max(f[i - 1][j], f[i][j + 1]));
        std::cout << f[n][1] << std::endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/hkttg/p/9403789.html