您的位置:首页 > 其它

【bzoj3997】[TJOI2015]组合数学

2017-04-11 16:12 381 查看
题目链接

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, m, t;
ll f

;

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
[1]);
}
}

int main(){
work();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: