zoukankan      html  css  js  c++  java
  • HDU_6017_Girls love 233_(dp)(记忆化搜索)

    Girls Love 233

     
     Accepts: 30
     
     Submissions: 218
     Time Limit: 2000/1000 MS (Java/Others)
     
     Memory Limit: 65536/65536 K (Java/Others)
    问题描述
    除了翘课以外,结识新的妹子也是呃喵重要的日程安排之一。
    这不,呃喵又混进了一个叫做ACgirls的女生群里,来达成自己不可描述的目的。
    然而,呃喵只会喵了个咪地说话,于是很容易引起注意。为了掩饰自己的真实身份,呃喵每次说话都小心翼翼。
    她知道,很多女生都喜欢说"233",然而呃喵想说的话一开始就确定好了,所以她要对这句话做修改。
    这句话的长度为n,语句里的字符不是'2'就是'3'。
    呃喵的智力非常有限,只有m点。她每次操作可以交换两个相邻的字符,然而代价是智力-2。
    现在问你,在使得自己智力不降为负数的条件下,呃喵最多能使这个字符串中有多少个子串"233"呢?
    如"2333"中有一个"233","232323"中没有"233"
    输入描述
    第一行为一个整数T,代表数据组数。
    接下来,对于每组数据——
    第一行两个整数n和m,分别表示呃喵说的字符串长度 以及呃喵的智力
    第二行一个字符串s,代表呃喵具体所说的话。
    
    数据保证——
    1 <= T <= 1000
    对于99%的数据,1 <= n <= 10, 0 <= m <= 20
    对于100%的数据,1 <= n <= 100, 0 <= m <= 100
    输出描述
    对于每组数据,输出一行。
    该行有1个整数,表示最多可使得该字符串中有多少个"233"
    输入样例
    3
    6 2
    233323
    6 1
    233323
    7 4
    2223333
    输出样例
    2
    1
    2

    一直没有思路,然后看了题解。。。

    思路:和官方题解思路差不多。记忆化搜索。用时间戳来避免重复的memset。

    做了这些比较基础的分析之后,基于数据规模很小,我们可以用以下4个要素表示完整的状态:

    1.处理到第几个'2'

    2.上一个'2'停留在什么位置,如果当前的'2'与上一个'2'距离相差>=2时则对答案+1

    3.呃喵的剩余交换次数是多少

    4.当前已经成功得到几个"233"

    而这四个要素的大小,最坏情况下分别是n、n、m、n级别的数,我们随便以3个要素作为下标对应状态,使得第4个要素最优做DP. 转移的时候步长也是不超过2m的,所以很容易就可以得出复杂度为O(n * n * m/2 * m)的算法。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<stdlib.h>
    using namespace std;
    
    char num[105];
    int dp[105][105][105],dfn[105][105][105];
    int p2[105],cnt2,len,cas;
    
    int dfs(int n,int lp,int tim)
    {
        if(n>cnt2)
            return (len-lp>=2);
        if(dfn[n][lp][tim]==cas)
            return dp[n][lp][tim];
        int l=max(lp+1,p2[n]-tim);
        int r=min(len,p2[n]+tim);
        dp[n][lp][tim]=-1e9;    //这个地方赋值为-1就会wa,不知道为啥。。。
        dfn[n][lp][tim]=cas;
        for(int i=l;i<=r;i++)
        {
            int cost=abs(p2[n]-i);
            dp[n][lp][tim]=max(dp[n][lp][tim],dfs(n+1,i,tim-cost)+(i-lp>=3)*(n>1));
        }
        return dp[n][lp][tim];
    }
    
    int main()
    {
        int t;
        scanf("%d",&t);
        for(cas=1;cas<=t;cas++)
        {
            int n,m;
            scanf("%d%d%s",&n,&m,num+1);
            len=n;
            m/=2;
            cnt2=0;
            for(int i=1;i<=len;i++)
                if(num[i]=='2')
                    p2[++cnt2]=i;
            if(cnt2==0)
            {
                puts("0");
                continue;
            }
            int ans=dfs(1,0,m);
            printf("%d
    ",ans);
            //cout<<dp[1][0][m/2]<<endl;
        }
        return 0;
    }
    
    
  • 相关阅读:
    java集合Collection常用方法详解
    JavaWeb_cookie和session
    JavaWeb_Cookie
    Java中双向链表
    Java链表基础
    select函数详解及实例分析
    socket select函数的详细讲解
    记录远程用户登录日志
    MSSQL grant
    dll 中使用ADO
  • 原文地址:https://www.cnblogs.com/jasonlixuetao/p/6479311.html
Copyright © 2011-2022 走看看