• 【BZOJ3997】【TJOI2015】组合数学 Dilworth定理 DP


    题目描述

      有一个(n imes m)的网格图,其中某些格子有财宝,每次从左上角出发,只能向下或右走。问至少走多少次才能将财宝捡完。

      此对此问题变形,假设每个格子中有好多财宝,而每一次经过一个格子至多只能捡走一块财宝,至少走多少次才能把财宝全部捡完。

      (n,mleq 1000)

    题解

      定义偏序关系

      把一个格子拆成很多个点,每个点代表一个财宝。

      对于两个点(a,b),称(a<b)当且仅当(a)能走到(b)

      那么这道题求的是最小链覆盖

      根据Dilworth定理,最小链覆盖数(=)最长反链长度。

      直接DP就行了。

      设(f_{i,j})为以((i,j))为结尾的最长反链长度

    [f_{i,j}=a_{i,j}+max_{k>i,l<j}f_{k,l} ]

      时间复杂度:(O(nm))

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int s[1010][1010];
    int f[1010][1010];
    int a[1010][1010];
    void solve()
    {
    	int n,m;
    	scanf("%d%d",&n,&m);
    	int i,j;
    	for(i=1;i<=n;i++)
    		for(j=1;j<=m;j++)
    			scanf("%d",&a[i][j]);
    	memset(s,0,sizeof s);
    	memset(f,0,sizeof f);
    	int ans=0;
    	for(i=n;i>=1;i--)
    		for(j=1;j<=m;j++)
    		{
    			s[i][j]=max(s[i][j],s[i][j-1]);
    			s[i][j]=max(s[i][j],s[i+1][j]);
    			f[i][j]=s[i][j]+a[i][j];
    			ans=max(ans,f[i][j]);
    			s[i-1][j+1]=f[i][j];
    		}
    	printf("%d
    ",ans);
    }
    int main()
    {
    	int t;
    	scanf("%d",&t);
    	while(t--)
    		solve();
    	return 0;
    }
    
  • 相关阅读:
    第一课:神经网络与机器学习
    自然语言基础之分词、标注、命名实体识别
    工程能力-语言-框架
    二叉树
    spark入门
    微平台推荐系统介绍(基于java)
    简历项目的梳理和面试准备
    统计学习方法李航学习笔记
    NopCommerce fluent validation使用
    NopCommerce支持多语言
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8514598.html
Copyright © 2020-2023  润新知