[TJOI2015]组合数学

[TJOI2015]组合数学

洛谷题目链接
这道题的码量不大,代码没什么难度,但是思维难度会比较大。
注意,有T组数据,每次都需要初始化,并且需要开long long


解释

我们有一个神奇的定理叫做Dilworth定理
即:最长反链=最小链覆盖=最大独立集。
这道题其实就是求最小链覆盖。
最小链覆盖:用最少的链让每一个点都在至少一个链中。
最长反链:即最长的反链。
反链:链中所有的点都是偏序关系。
偏序:非正序,在本题中只能向下和向右,所以向上和向左即为偏序。
最大独立集:最大的集合,其中相互两点无法到达。
至于为什么相等,证明很麻烦我不会,但是仔细想想是能理解的。


题解

我们在这个题中需要求出最长反链,我们用dp来求。
由于是反链,我们的\(f_{i,j}\)可以从\(f_{i-1,j}\)和\(f_{i,j+1}\)转移,如果是右上\(f_{i-1,j+1}\)到\(f_{i,j}\)我们就需要宝藏数次(因为一次只能取一个),也就是:
\(f_{i,j}=max(f_{i-1,j},f_{i,j+1},f_{i-1,j+1}+a_{i,j})\)


标程

#include<bits/stdc++.h>
using namespace std;
const int MN=1010;
#define int long long
int T,n,m;
int a[MN][MN],dp[MN][MN];
void init(){memset(a,0,sizeof(a)),memset(dp,0,sizeof(dp));}
signed main(){
	//freopen("math.in","r",stdin);
	//freopen("math.out","w",stdout);
	scanf("%lld",&T);
	while(T--){
		init();
		scanf("%lld%lld",&n,&m);
		for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)scanf("%lld",&a[i][j]);
		for(int i=1;i<=n;++i){
			for(int j=m;j>=1;--j){
				dp[i][j]=max(dp[i-1][j],max(dp[i][j+1],dp[i-1][j+1]+a[i][j]));
			}
		}
		printf("%lld\n",dp[n][1]);
	}
	return 0;
} 
上一篇:A-color-image-encryption-technique-using-exclusive-OR-with-DNA-complementary-rules-based-on-chaos...


下一篇:Codeforces Round #695 (Div. 2)