zoukankan      html  css  js  c++  java
  • 入门dp(续更)

    问题 H: 【动态规划】fstring字符串

    时间限制: 1 Sec  内存限制: 64 MB
    提交: 39  解决: 13
    [提交] [状态] [命题人:外部导入]

    题目描述

    一个只包含A,B,C三种字符的字符串,如果其中有连续的3个由A,B,C各一个组成的子串,则称这个字符串为fstring字符串。
    例如:BAACAACCBAAA就是一个fstring字符串,而AABBCCAABB则不是。
    你的任务是计算只包含A,B,C三种字符且长度为n的这种字符串有多少个不是fstring字符串。

     

    输入

    一个整数n(l≤n≤30)。

     

    输出

    一个整数。

     

    样例输入

    3
    

    样例输出

    21
    

     

    提示

     

    另一组数据 输入2输出9

     

    这个是网易的试题,要求连续三个字符不是ABC的组合,一个可行的思路是——
    f[i]表示长度i的字符串的可行方案。
    假设该判断第n个字符了,那么决定这个字符的是第n-1,n-2个字符,
    如果n-1,n-2相同,
    那么f[i-1]必然等于f[i-2],n可以取任意一个字符,所以f[i]=3*f[i-1]。
    如果不相同,那么n取n-1,n-2中的一个,也就是f[i]=(f[i-1]-f[i-2])*2。
    综上,f[i]=(f[i-1]-f[i-2])*2+f[i-1]*3。
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=1e6+5;
    ll a[maxn];
    int main()
    {
        int n;
        cin>>n;
        a[1]=3;
        a[2]=9;
        for(int i=3;i<=n;i++)
        {
            a[i]=3*a[i-2]+2*(a[i-1]-a[i-2]);
        }
        cout<<a[n]<<endl;
        return 0;
    }
    View Code

    问题 I: 【动态规划】桐桐的爬山计划

    时间限制: 1 Sec  内存限制: 64 MB
    提交: 9  解决: 3
    [提交] [状态] [命题人:外部导入]

    题目描述

    桐桐一直有个梦想,很希望像“蜘蛛人”罗伯特一样飞檐走壁。为了达成这个梦想,桐桐每天都辛勤练习攀爬。练习的出发点与终点都是在地上面。给出一个数列,代表她每次移动的距离。这个移动可以向上,也可以向下。但是不可能到达地下面去的。而她做练习使用的建筑物总是比她到达过的最高位置高2米。现在我们希望这个建筑物的高度越小越好。
    如:20 20 20 20
    如果是上,上,下,下的话,这个建筑物就要42米高,如果是上,下,上,下,就只要22米高。
    当然有些数列是无解的,例如:3421645。

     

    输入

    第1行输入n(n≤l00),代表有n个爬行距离;
    第2行输入n个爬行距离(均为整数),这些爬行距离的总和不超过10000。

     

    输出

    如果有解,则输出最小的高度;
    否则输出’IMPOSSIBLE’。

     

    样例输入

    4
    20 20 20 20
    

    样例输出

    22
    

     这个题的思路并不显然,翻了翻题解加上思考才算搞定。

    用f[i][j]表示第i次爬行,且当前处于高度j时到达过的最大高度

    对于每一个爬行距离tmp,从0到最大值之间查找由i-1转移的状态,也即

    f[i][j]——>f[i-1][j+tmp] 或者f[i-1][j-tmp]

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #define MAXN 101
     
    using namespace std;
     
    int n;
    int a[MAXN][10001]; //达到过的最高高度
    // 一维: 第几次爬行
    // 二维: 目前达到的高度
     
    int main()
    {
        scanf("%d", &n);
        int maxnow = 0;
        for(register int i = 1, tmp; i <= n; i++)
        {
            scanf("%d", &tmp);
            maxnow += tmp;
            if(i == 1) a[1][tmp] = tmp;
            else for(register int j = 0; j <= maxnow; j++)
                {
                    if((j - tmp < 0 || !a[i - 1][max(0, j - tmp)]) && (j + tmp > maxnow || !a[i - 1][min(maxnow, j + tmp)]))
                        continue;
                    if(j - tmp < 0 || !a[i - 1][max(0, j - tmp)])
                        a[i][j] = max(j, a[i - 1][j + tmp]);
                    else if(j + tmp > maxnow || !a[i - 1][j + tmp])
                        a[i][j] = max(j, a[i - 1][j - tmp]);
                    else
                        a[i][j] = max(j, min(a[i - 1][j - tmp],a[i - 1][j + tmp]));
                }
        }
        a[n][0] ? printf("%d", a[n][0] + 2) : puts("IMPOSSIBLE");
        return 0;
    }
    View Code

    问题 J: 【动态规划】多米诺骨牌问题

    时间限制: 1 Sec  内存限制: 128 MB
    提交: 27  解决: 6
    [提交] [状态] [命题人:admin]

    题目描述

    有一种多米诺骨牌是平面的,其正面被分成上下两个部分,每一部分的表面或者为空,或者被标上1至6个点。现在有一行多米诺骨牌排列在桌面上,如下图所示: 

    顶行(上行)骨牌的点数之和为6+1+1+1=9;底行(下行)骨牌的点数之和为1+5+3+2=11。顶行和底行的差值是2,这个差值是上下两行点数之和的差的绝对值。每个多米诺骨牌都可以上下翻转倒置交换,即上部变为下部,下部变为上部。

    现在的任务是,以最少的翻转次数,使得顶行和底行之间的差值最小。对于上面这个例子,我们只需要翻转最后一个骨牌,就可以使得顶行和底行的差值为0。所以这个例子的答案为1。

     

    输入

    输入的第1行是一个整数n(1<=n<=1000),表示有n个多米诺骨牌在桌面上排成一行。接下来总共有n行,每行包含两个整数 a,b(0<=a,b<=6,中间用空格分开)。第i+1行的a,b分别表示第i个多米诺骨牌的上部和下部的点数(0表示空)。

     

    输出

    输出只有一个整数。这个整数表示翻动骨牌的最少次数,从而使得顶行和底行的差值最小。

     

    样例输入

    4
    6 1
    1 5
    1 3
    1 2
    

    样例输出

    1
    可以当成01背包问题解决,翻与不翻对应选与不选两种状态,这样思路就很清晰了
    #include <bits/stdc++.h>
     
    using namespace std;
    int a[1005],b[1005],dp[6010];
    const int  inf=0x3f3f3f3f;
    int main()
    {
        int n;
        scanf("%d",&n);
        int s=0,m=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&a[i],&b[i]);
            s+=max(a[i],b[i]);
            m+=a[i]+b[i];
        }
        memset(dp,inf,sizeof dp);
        dp[0]=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=s;j>=0;j--)
            {
                int ans=inf;
                if(j>=a[i])
                {
                    ans=dp[j-a[i]];
                }
                if(j>=b[i])
                {
                    ans=min(dp[j-b[i]]+1,ans);
                }
                dp[j]=ans;
            }
        }
        int k=inf;
        for(int i=m>>1;i>=0;i--)
        {
            k=min(dp[i],dp[m-i]);
            if(k<inf)
            {
                printf("%d
    ",k);
                return 0;
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Lucene.Net 2.3.1开发介绍 —— 二、分词(一)
    控制‘控制台应用程序’的关闭操作
    详解for循环(各种用法)
    敏捷软件开发
    Sql Server的一些知识点
    在SharePoint 2010 中配置Remote Blob Storage FILESTREAM Provider
    使用LotusScript操作Lotus Notes RTF域
    JOpt Simple 4.5 发布,命令行解析器
    John the Ripper 1.8.0 发布,密码破解工具
    PacketFence ZEN 4.0.1 发布,网络接入控制
  • 原文地址:https://www.cnblogs.com/Suiyue-Li/p/11086928.html
Copyright © 2011-2022 走看看