• 洛谷P2362 围栏木桩----dp思路


    在翻dp水题的时候找到的有趣的题0v0

    原文>>https://www.luogu.org/problem/show?pid=2362<<

    题目描述

    某农场有一个由按编号排列的n根木桩构成的首尾不相连的围栏。现要在这个围栏中选取一些木桩,按照原有的编号次序排列之后,这些木桩高度成一个升序序列。所谓的升序序列就是序列中的任何一个数都不小于它之前的任何一个数。试编写程序从这个围栏中选取合适的木桩使得选出的木桩个数t最大,并求出选取出t根木桩的方案总数c。

    输入输出格式

    输入格式:

     

    文件中的第一行只有一个数m,表明随后有m个问题的描述信息。每个问题的描述信息格式为n h1,h2,h3,…,hn(其中hi(i=1,2,3,…,n)表示第i根木桩的高度。)

     

    输出格式:

     

    依次输出每个问题中t和c的解。每行输出一个问题的解。

    这题和一般最长不下降子序列的区别就在于他需要输出最大解的种类个数.怎么统计这些可能解就是这题有意思的地方.

    我们通过a数组存序列,b来记录前i个数的最长子序列,最关键的是c,c[i]的意义是记录在1~i-1中满足最大序列为b[i]-1的子序列个数.

    挺难理解,我举个例子:

    给8个数字 17534851 当i=3时 b[3]=2 (15或17) c[3]则表示当i=1~2中满足b[i]=1的情况 显然只有i=1时(i=2时b[2]=2) 所以c[3]=1;

    i=4时 b[4]=2 c[4]=1;i=5时 b[5]=3 (134) c[5]=3 (i=2,3,4时c[i]为2).

    于是乎,i=n时最长序列就在b里找,假设找到最大值bmax,而可能的情况则为 for(i=1;i<=n;i++) if(b[i]=bmax) ans+=c[i];

    为什么会有这样的关系?我们在开始时先给 b c 数组赋初值1(序列最短可为自己本身),之后的讨论都是建立在a[i]>=a[r]上的.所以要在第一个循环前加上判断条件if(a[i]>=a[r]) (r的出处请脑补最长不下降子序列模板),bmax对应的c[i]意为不包括a[i]在内的最大序列为bmax-1的情况.所以如果在尾部加上a[i],最长数目就变成了bmax.这就是该算法的原理.觉得理解不充分的话可以自己举一个例子套套看,与代码结合也许会有助于理解.

    #include<iostream>
    using namespace std;
    int main()
    {
        int k,n,b[2005],c[2005],a[2005],i,j;
        cin>>k;
        while(k--)
        {
            cin>>n;
            for(i=1;i<=n;i++) 
            {
                cin>>a[i];
                b[i]=c[i]=1;
            }
            for(j=2;j<=n;j++)
            {
                int r;
                for(r=j-1;r>=1;r--)
                {
                    if(a[j]>=a[r])
                    {
                        if(b[j]<b[r]+1)
                        {
                            b[j]=b[r]+1;
                            c[j]=c[r];
                        }
                        else if(b[j]==b[r]+1)
                        {
                            c[j]+=1;
                        }
                    }
                }
                
            }
            int max=-1,bj=0;
            for(i=1;i<=n;i++)
            {
                if(b[i]>max)
                {
                    max=b[i];
                    bj=i;
                }
            }
            int ans=0;
            for(i=1;i<=n;i++)
            {
                if(b[i]==b[bj]) ans+=c[i];
            }
            cout<<b[bj]<<" "<<ans<<endl;
        }
    }
     
  • 相关阅读:
    学算法还能指导找对象?是的,这就是大名鼎鼎的稳定婚姻算法
    机器学习 | 详解GBDT梯度提升树原理,看完再也不怕面试了
    Python | 面试的常客,经典的生产消费者模式
    LeetCode 89,因为题目晦涩而被点了1500+反对的搜索问题
    LeetCode 87,远看是字符串其实是搜索,你能做出来吗?
    Golang | Go语言多态的实现与interface使用
    pandas | DataFrame基础运算以及空值填充
    算法数据结构 | 只要30行代码,实现快速匹配字符串的KMP算法
    Mac上使用Docker安装SQLServer
    [翻译]ASP.NET Core在 .NET 5 Preview 7的更新
  • 原文地址:https://www.cnblogs.com/wsblm/p/7096844.html
Copyright © 2020-2023  润新知