[BZOJ 3997] 组合数学

题意

  给定 $n \times m$ 的网格图, 每个格子有 $w$ 个财宝.

  每次从左上角出发到右下角, 将途中经过的所有格子中的财宝至多拿一个.

  问最少多少次能拿完所有财宝.

  $n, m \le 1000$ .

分析

  根据 Dilworth 定理, 最少链划分 = 最大反链长度.

  从左下角到右上角进行 DP .

实现

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cctype>
 5 #include <algorithm>
 6 using namespace std;
 7 #define F(i, a, b) for (register int i = (a); i <= (b); i++)
 8 #define P(i, a, b) for (register int i = (a); i >= (b); i--)
 9 #define LL long long
10 inline int rd(void) {
11     int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == ‘-‘) f = -1;
12     int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-‘0‘; return x*f;
13 }
14
15 const int N = 1005;
16
17 int n, m, w[N][N];
18 LL f[N][N];
19
20 int main(void) {
21     #ifndef ONLINE_JUDGE
22         freopen("bzoj3997.in", "r", stdin);
23     #endif
24
25     for (int nT = rd(); nT > 0; nT--) {
26         n = rd(), m = rd();
27         F(i, 1, n) F(j, 1, m) w[i][j] = rd();
28
29         memset(f, 0, sizeof f);
30         P(i, n, 1)
31             F(j, 1, m) {
32                 f[i][j] = max(f[i][j-1], f[i+1][j]);
33                 f[i][j] = max(f[i][j], f[i+1][j-1] + w[i][j]);
34             }
35         printf("%lld\n", f[1][m]);
36     }
37
38     return 0;
39 }
时间: 2024-10-12 07:52:55

[BZOJ 3997] 组合数学的相关文章

bzoj 3997: [TJOI2015]组合数学

3997: [TJOI2015]组合数学 Description 给出一个网格图,其中某些格子有财宝,每次从左上角出发,只能向下或右走.问至少走多少次才能将财宝捡完.此对此问题变形,假设每个格子中有好多财宝,而每一次经过一个格子至多只能捡走一块财宝,至少走多少次才能把财宝全部捡完. Input 第一行为正整数T,代表数据组数. 每组数据第一行为正整数N,M代表网格图有N行M列,接下来N行每行M个非负整数,表示此格子中财宝数量,0代表没有 Output 输出一个整数,表示至少要走多少次. Samp

【BZOJ 3997】 3997: [TJOI2015]组合数学 (DP| 最小链覆盖=最大点独立集)

3997: [TJOI2015]组合数学 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 919  Solved: 664 Description 给出一个网格图,其中某些格子有财宝,每次从左上角出发,只能向下或右走.问至少走多少次才能将财宝捡完.此对此问题变形,假设每个格子中有好多财宝,而每一次经过一个格子至多只能捡走一块财宝,至少走多少次才能把财宝全部捡完. Input 第一行为正整数T,代表数据组数. 每组数据第一行为正整数N,M代表网格图有

[BZOJ 3997] [TJOI 2015] 组合数学

3997: [TJOI2015]组合数学 Time Limit: 20 SecMemory Limit: 128 MB Description 给出一个网格图,其中某些格子有财宝,每次从左上角出发,只能向下或右走.问至少走多少次才能将财宝捡完.此对此问题变形,假设每个格子中有好多财宝,而每一次经过一个格子至多只能捡走一块财宝,至少走多少次才能把财宝全部捡完. Input 第一行为正整数T,代表数据组数. 每组数据第一行为正整数N,M代表网格图有N行M列,接下来N行每行M个非负整数,表示此格子中财

BZOJ 3997 [TJOI2015]组合数学(单调DP)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3997 [题目大意] 给出一个网格图,其中某些格子有财宝,每次从左上角出发,只能向下或右走. 问至少走多少次才能将财宝捡完.此对此问题变形,假设每个格子中有好多财宝, 而每一次经过一个格子至多只能捡走一块财宝,至少走多少次才能把财宝全部捡完. [题解] 最小链覆盖=最长反链,反链的意思就是该集合中的点相互之间不互达, 在该题中,最长反链可以用dp得出. [代码] #include <c

BZOJ 3997 [TJOI 2015 组合数学] 解题报告

这个题我脑洞了一个结论: 首先,我们定义满足以下条件的路径为“从右上到左下的路径”: 对于路径上任何不相同的两个点 $(x_1, y_1)$,$(x_2, y_2)$,都有: $x_1\neq x_2, y_1\neq y_2$ 若 $x_1 > x_2$,则有 $y_1 < y_2$:否则当 $x_1 < x_2$ 时, $y_1 > y_2$. 然后我们找到所有从右上到左下的路径,其中路径的权值和最大的那条路径的权值和就是答案了. 然后我们就可以用 Dp 解决问题了. 我们可以

BZOJ 3997 TJOI2015 组合数学 Dilworth定理

题目大意:给定一个网格图,每次从左上角出发,只能往右或往下走,最后到达右下角,每个格子有最低经过次数,问最少走几次 Dilworth定理:DAG的最小链覆盖=最大点独立集 最小链覆盖指选出最少的链(可以重复)使得每个点都在至少一条链中 最大点独立集指最大的集合使集合中任意两点不可达 此题中最大点独立集显然是一个集合满足集合中任意两点都是左下-右上的关系 DP一遍就能出解 复杂度O(Tmn) #include <cstdio> #include <cstring> #include

bzoj 3997 Dilworth定理

看到这道题感觉像是网络流,如果没有权值,可以用DAG最小路径覆盖,有权值,感觉可以求一个上下界最小可行流,但内存卡了....时间估计也悬. 正解要用到一些数学知识,这里梳理一下: 定义: 偏序关系: 满足自反,反对称,传递的关系是自反关系 链: 偏序集A的一个子集B,并且满足B中元素两两可比 反链: 偏序集A的一个子集B,并且满足B中元素两两不可比 集合的划分: 集合A的划分是很多个集合,这些集合的交集为空,并集为A Dilworth定理: 偏序集的最长反链的大小等于最小链划分 另一个定理: 偏

BZOJ 1008 越狱 (组合数学)

题解:正难则反,从总数中减去全部相邻不相同的数目就是答案,n*(n-1)^(m-1):第一个房间有n中染色方案,剩下m-1个房间均只有n-1种染色方案,用总数减就是答案. #include <cstdio> const int mod=100003; typedef long long LL; LL n,m; LL power(LL a,LL b){ LL ans=1; a%=mod; while(b){ if(b&1)ans=ans*a%mod; a=a*a%mod,b>>

BZOJ 1005 明明的烦恼 (组合数学)

题解:n为树的节点数,d[ ]为各节点的度数,m为无限制度数的节点数. 则             所以要求在n-2大小的数组中插入tot各序号,共有种插法: 在tot各序号排列中,插第一个节点的方法有种插法: 插第二个节点的方法有种插法: ......... 另外还有m各节点无度数限制,所以它们可任意排列在剩余的n-2-tot的空间中,排列方法总数为 根据乘法原理: #include <cstdio> #include <cmath> int n,m,tot,i,j,d,down