码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2018-03-06 17:07:06      阅读:180      评论:0      收藏:0      [点我收藏+]

标签:根据   mat   span   题目   gpo   eof   时间复杂度   复杂   algorithm   

题目描述

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

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

  \(n,m\leq 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\n",ans);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
        solve();
    return 0;
}

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

标签:根据   mat   span   题目   gpo   eof   时间复杂度   复杂   algorithm   

原文地址:https://www.cnblogs.com/ywwyww/p/8514598.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!