1. 程式人生 > >[BZOJ 3997] 組合數學

[BZOJ 3997] 組合數學

pri for 一個 每次 space lib span name online

題意

  給定 $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 }

[BZOJ 3997] 組合數學