题意
给定 $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