bzoj 3997: [TJOI2015]组合数学

3997: [TJOI2015]组合数学

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

 

#include<stdio.h>
#include<iostream>
using namespace std;
const int N=1005;
int T,n,m,i,j,a[N][N],f[N][N];
inline void read(int &v){
    char ch,fu=0;
    for(ch='*'; (ch<'0'||ch>'9')&&ch!='-'; ch=getchar());
    if(ch=='-') fu=1, ch=getchar();
    for(v=0; ch>='0'&&ch<='9'; ch=getchar()) v=v*10+ch-'0';
    if(fu) v=-v;
}
int main()
{
    read(T);
    while(T--)
    {
        read(n),read(m);
        for(i=1;i<=n;i++)
         for(j=m;j>=1;j--) read(a[i][j]);
        for(i=1;i<=n;i++)
         for(j=1;j<=m;j++)
         f[i][j]=max(f[i-1][j-1]+a[i][j],max(f[i-1][j],f[i][j-1]));
        printf("%d\n",f[n][m]);
    }
    return 0;
}

 

  

 

posted @ 2016-07-12 20:08  lwq12138  阅读(228)  评论(0编辑  收藏  举报