T2 P3974 [TJOI2015]组合数学
思路:
只能从左上到右下
考虑左上的点向右下的点连边,然后在图上最小链覆盖,链的条数即为步数
根据 Dilworth定理,最小链覆盖条数等于最长反链长度
证明:
最长反链的点之间不能互相到达,至少需要走这几个点才能全部取完
于是从左下到右上暴力 dp
转移方程:
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
]
[
j
]
,
d
p
[
i
]
[
j
−
1
]
,
d
p
[
i
+
1
]
[
j
]
,
d
p
[
i
+
1
]
[
j
−
1
]
+
a
[
i
]
[
j
]
)
dp[i][j]=max(dp[i][j],dp[i][j-1],dp[i+1][j],dp[i+1][j-1]+a[i][j])
dp[i][j]=max(dp[i][j],dp[i][j−1],dp[i+1][j],dp[i+1][j−1]+a[i][j])
代码:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
inline int in{
int s=0,f=1;char x;
for(x=getchar();x<'0'||x>'9';x=getchar()) if(x=='-') f=-1;
for( ;x>='0'&&x<='9';x=getchar()) s=(s*10)+(x&15);
return f==1?s:-s;
}
const int A=1e3+5;
int T;
int n,m;
int a[A][A];
int dp[A][A];
signed main(){
T=in;
while(T--){
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
dp[i][j]=0;
n=in,m=in;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
a[i][j]=in;
for(int i=n;i;i--){
for(int j=1;j<=m;j++){
dp[i][j]=max(dp[i][j],dp[i][j-1]);
dp[i][j]=max(dp[i][j],dp[i+1][j]);
dp[i][j]=max(dp[i][j],dp[i+1][j-1]+a[i][j]);
}
}
printf("%d\n",dp[1][m]);
}
return 0;
}