【bzoj3997】[TJOI2015]组合数学

来源:互联网 发布:mac win触摸板难用 编辑:程序博客网 时间:2024/06/04 17:52

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

题解
结论题,我只能意会。当一个点在另一个点的左下角时,他们的路径是不会重复的,所以从左下角到右上角跑一个最长路DP
dp[i][j]=max(dp[i+1][j-1]+a[i][j],max(dp[i][j-1],dp[i+1][j]));

代码

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<set>#include<ctime>#include<vector>#include<cmath>#include<algorithm>#include<map>#include<queue>#define mod 1000000009 #define ll long long  using namespace std;inline int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}int n,m,a[1005][1005],dp[1005][1005];void solve(){    n=read();m=read();    for (int i=1;i<=n;i++)        for (int j=1;j<=m;j++)            a[i][j]=read();    for (int i=n;i;i--)        for (int j=1;j<=m;j++)            dp[i][j]=max(dp[i+1][j-1]+a[i][j],max(dp[i][j-1],dp[i+1][j]));    printf("%d\n",dp[1][n]);}int main(){    int Case=read();    while (Case--) solve();    return 0;}
原创粉丝点击