ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[TJOI2015]组合数学

2021-08-08 18:32:55  阅读:200  来源: 互联网

标签:偏序 组合 int MN long 数学 TJOI2015 反链 dp


[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;
} 

标签:偏序,组合,int,MN,long,数学,TJOI2015,反链,dp
来源: https://www.cnblogs.com/fanner-Blog/p/15115664.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有