Description
给出一个网格图,其中某些格子有财宝,每次从左上角出发,只能向下或右走。问至少走多少次才能将财宝捡完。此对此问题变形,假设每个格子中有好多财宝,而每一次经过一个格子至多只能捡走一块财宝,至少走多少次才能把财宝全部捡完。
Input
第一行为正整数T,代表数据组数。
每组数据第一行为正整数N,M代表网格图有N行M列,接下来N行每行M个非负整数,表示此格子中财宝数量,0代表没有
Output
输出一个整数,表示至少要走多少次。
Sample Input
1
3 3
0 1 5
5 0 0
1 0 0
Sample Output
10
HINT
N<=1000,M<=1000.每个格子中财宝数不超过10^6
题解
Dilworth定理:DAG的最小链覆盖=最大点独立集。
头一次知道这个定理居然还有个名字。
那么这题就是求最大点独立集,显然是一个从右上到左下的点的集合。
直接DP求解就好了。
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)) { if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
typedef long long ll;
const int N = 1000 + 10;
int a[N][N], n, m, t;
ll f[N][N];
void init(){
n = read(), m = read();
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
a[i][j] = read();
memset(f, 0, sizeof(f));
}
void work(){
t = read();
while(t--){
init();
for(int i = 1; i <= n; i++)
for(int j = m; j >= 1; j--)
f[i][j] = max(f[i-1][j+1] + a[i][j], max(f[i-1][j], f[i][j+1]));
printf("%lld\n", f[n][1]);
}
}
int main(){
work();
return 0;
}