zoukankan      html  css  js  c++  java
  • 试题 算法提高 天天向上(dfs、dp)

    问题描述
      A同学的学习成绩十分不稳定,于是老师对他说:“只要你连续4天成绩有进步,那我就奖励给你一朵小红花。”可是这对于A同学太困难了。于是,老师对他放宽了要求:“只要你有4天成绩是递增的,我就奖励你一朵小红花。”即只要对于第i、j、k、l四天,满足i<j<k<l并且对于成绩wi<wj<wk<wl,那么就可以得到一朵小红花的奖励。现让你求出,A同学可以得到多少朵小红花。
    输入格式
      第一行一个整数n,表示总共有n天。第二行n个数,表示每天的成绩wi。
    输出格式
      一个数,表示总共可以得到多少朵小红花。
    样例输入
    6
    1 3 2 3 4 5
    样例输出
    6
    数据规模和约定
      对于40%的数据,n<=50;
      对于100%的数据,n<=2000,0<=wi<=1e9。
    思路
    1.记忆化搜索
    维护一个二维数组dp,pos代表当前位置,cnt代表是作为递增的第cnt天。dp[pos][cnt]存的是当前位置作为递增的第cnt天到cnt=4所能得到的方案数。
    累加除倒数3个数的其余数作为递增序列的第一天的方案数即是答案。
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long int ll;
    ll a[2005];
    ll dp[2005][5];
    ll n,p,t;
    ll dfs(int pos,int cnt){
        if(cnt==4)return 1;///达到4个递增数字,返回1
        if(dp[pos][cnt]!=-1)return dp[pos][cnt];///记忆化
        ll c=0;///当前位置的递增天数到能满足递增4天的方案数,注意是局部变量
        for(int i=pos+1;i<n;i++){
            if(a[i]>a[pos]){
                c+=dfs(i,cnt+1);
            }
        }
         return dp[pos][cnt]=c;///记忆一波返回
    }
    int main(){
        cin>>n;
        memset(dp,-1,sizeof(dp));
        for(int i=0;i<n;i++)cin>>a[i];
        ll ans=0;
        for(int i=0;i<n-3;i++){
            ans+=dfs(i,1);///累加每个数作为递增序列的第一个的方案数,后3个除外
        }
        cout<<ans<<endl;
        return 0;
    }
    2.动态规划
    这里的dp[i][k]这里代表从i天开始递增k个数的方案数。
    默认递增1个数自己本身为1个,我们理解dp[i][k]等于 数值比a[i]大的且位置比i后的j, 且递增的个数为k-1的方案数累加得到。每次把所有j位置的所得到的不同的递增数的方案转移到i上。
    从后往前递推,状态转移方程dp[i][j]= ∑dp[k][j-1] (k>i,a[k]>a[i]),转移过程中当方案数不存在时退出。
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long int ll;
    ll a[2005];
    ll dp[2005][5];
    ll n,p,t;
    int main(){
        cin>>n;
        for(int i=0;i<n;i++)cin>>a[i];
        for(int i=n-1;i>=0;i--){
            dp[i][1]=1;///第一个递增数为自己
            for(int j=i+1;j<n;j++){
                if(a[i]<a[j]){///如果后面的数比i大
                    int k=2;///从使递增数为2开始
                    while(k<=4){
                        if(dp[j][k-1]==0)break;
                        dp[i][k]+=dp[j][k-1];
                        k++;
                    }
                }
            }
        }
        ll ans=0;
        for(int i=0;i<n-3;i++){
            ans+=dp[i][4];
        }
        cout<<ans<<endl;
        return 0;
    }
     
  • 相关阅读:
    05Linux文件修改
    07Linux基本权限
    09Linux软件安装
    搬家
    web项目和单元测试
    session_start() 对 HTTP_REQUEST扩展/fsockopen函数 的影响
    从不同架构的角度进行web项目的需求分析和系统设计
    程序中的风险控制
    【原创】 书籍推荐
    【转载】10个效果最佳的编程字体
  • 原文地址:https://www.cnblogs.com/mohari/p/13546099.html
Copyright © 2011-2022 走看看