• 【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;
    }
    
  • 相关阅读:
    Kubernetes 认证(证书)过期怎么办
    JavaScript 全屏显示窗口
    IE6下很无语的问题,不知为何
    项目开发-让设计模式成为一种心智(转)
    CSS中Float概念相关文章采撷
    随记浏览器兼容性
    常用正则表达式
    ASP.NET 调用Delphi DLL问题
    ASP.NET调用DELPHI DLL
    转:Oracle 排序中常用的NULL值处理方法
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8514598.html
Copyright © 2020-2023  润新知