bzoj 3997 [TJOI2015]组合数学(DP)

时间:2023-03-09 13:02:55
bzoj 3997 [TJOI2015]组合数学(DP)

【题目链接】

http://www.lydsy.com/JudgeOnline/problem.php?id=3997

【题意】

给定一个nm的长方形,每次只能使经过格子权值减1,每次只能向右向下,问最少需要走多少次才能使所有格子权值为0.

【思路】

因为每次只能向右或向下走,所以对于(i,j)和(i’,j’)当且仅当两点任一个不在另一个的左下方时两点才不在同一条路径上。

将长方形反转左右。

设f[i][j]为使以ij右下角的长方形权值为0的走的最少次数,则有转移式:

f[i][j]=max{ max{ f[i-1][j],f[i][j-1] },f[i-1][j-1]+a[i][j] }

含义为选一个点集和最大的点集,使得点集中的任意两个节点满足不在同一条路径上,最大点集和即为答案。

【代码】

 #include<cstdio>
#include<cstring>
#include<iostream>
using namespace std; typedef long long ll;
const int N = 1e3+; int n,m;
int f[N][N],mp[N][N]; ll read() {
char c=getchar(); ll f=,x=;
while(!isdigit(c)) {
if(c=='-') f=-; c=getchar();
}
while(isdigit(c))
x=x*+c-'',
c=getchar();
return x*f;
} int main()
{
int T;
T=read();
while(T--) {
memset(f,,sizeof(f));
n=read(),m=read();
for(int i=;i<=n;i++) {
for(int j=m;j;j--) mp[i][j]=read();
}
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
f[i][j]=max(max(f[i-][j],f[i][j-]),f[i-][j-]+mp[i][j]);
printf("%d\n",f[n][m]);
}
return ;
}