一道DP的思考题

今天在群里面遇到了庆神提出的讨论题目:

 一个只包含'A','B','C'的字符串 求当长度为n时 有多少种可能情况使该串中不包含'ABC'三个连在一起不分先后的子串 

刚开始没什么思路,而且群里面讨论的很热烈,于是自己写了个爆搜

#include <iostream>
#include <queue>
#include <string>
using namespace std;
int built;
bool check(string& s)/// Return TRUE if No ERROR
{
    if(s.size()<3) return true;
    for(int i=0;i<=s.size()-3;i++)
    {
        int a=s.at(i);
        int _x=s.at(i+1);
        a^=_x;
        _x=s.at(i+2);
        a^=_x;
        if(a==built) return false;
    }
    return true;
}
int main()
{
    int n;
    built='a';
    int _x='b';
    built^=_x;
    _x='c';
    built^=_x;
    while(cin>>n)
    {
        queue<string> bus;
        int cnt=0;
        bus.push("a");
        bus.push("b");
        bus.push("c");
        while(!bus.empty())
        {
            string s=bus.front();
            bus.pop();
            if(check(s))
            {
                if(s.size()==n)
                {
                    cout<<s<<endl;
                    cnt++;
                    continue;
                }
                bus.push(s+"a");
                bus.push(s+"b");
                bus.push(s+"c");
            }
        }
        cout<<cnt<<endl;
    }
    return 0;
}
得到了一些结果,保证这是正确的

后来开始思考别的方法,发现所要求内容只与连续的三个字符有关,因此可以DP,那么DP维度就是四维

dp[i][j][k][m]=

0 (j,k,m不相同)

sum{cc=0~3 | dp[i-1][cc][j][k] }

其中i表示字串长度,j,k,m表示从后数第三位,第二位,第一位

初始化从i=3进行,i<3的时候可以直接输出答案(爆搜得到的)

于是代码如下

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
using namespace std;
#define foreach(ValName,From,Dest) for(int ValName=From;ValName<Dest;++ValName)
#define MAXN 35
long long dp[MAXN][3][3][3];

int main()
{
    int n;
    scanf("%d",&n);
    /// i=3
    foreach(j,0,3)
    foreach(k,0,3)
    foreach(m,0,3)
    {
        if(j!=k&&k!=m&&j!=m) dp[3][j][k][m]=0;
        else dp[3][j][k][m]=1;
    }


    /// i=4 ... 30
    foreach(i,4,n+1)
    {
        foreach(j,0,3)
        {
            foreach(k,0,3)
            {
                foreach(m,0,3)
                {
                    if(j!=k&&k!=m&&j!=m)
                    {
                        dp[i][j][k][m]=0;
                    }
                    else
                    {
                        //dp[i][j][k][m]=dp[i-1][?][j][k];
                        long long ans=0;
                        foreach(cc,0,3)
                        {
                            ans+=dp[i-1][cc][j][k];
                        }
                        dp[i][j][k][m]=ans;
                    }
                }
            }
        }
    }

    long long ans=0;
    foreach(j,0,3)
    foreach(k,0,3)
    foreach(m,0,3)
    ans+=dp[n][j][k][m];
    printf("%I64d\n",ans);
}

写完之后发现其实初始化可以合并到求值里面去,不过结果都一样,就不写了。

发给庆神之后居然被回复啦!好开心!对话过程中无时无刻不能感受到庆神那种谦逊!真心让人佩服!


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LPM_ROM和LPM_RAM设计 一 实验目的 掌握FPGA中LPM_ROM的设置: 1 作为只读寄存器ROM的工作特性和配置方法; 2 学习将程序代码或数据以MIF格式文件加载于LPM_ROM中; 掌握lpm_ram_dp的参数设置和使用方法: 1 掌握lpm_ram_dp作为随即存储器RAM的设置; 2 掌握lpm_ram_dp的工作特性和读写方法; 3 掌握lpm_ram_dp的仿真测试方法。 二 实验要求 1 LPM_ROM定制和测试 LPM_ROM的参数设置: LPM_ROM中数据的写入,即初始化文件的编写; LPM_ROM的实际应用,在GW48实验台上用N0.0电路模式测试。 2 LPM_RAM定制和测试 LPM_RAM的参数设置; LPM_RAM的实际应用,在GW48实验台上用N0.0电路模式测试。 三 实验原理 用户可编程硬件FPGA芯片设计,有许多可调用参数化库模块LPM(Library Parameterized Modules),课直接调用设置,利用嵌入式阵列块EAB(Embed Array Block)构成lpm_ROM,lpm_RAM等各种存储器结构。 Lpm_ROM有5组信号: 地执信号address[]; 数据信号q[]; 时钟信号inclock、outclock; 允许信号memenable. 其参数是可以设定的。由于ROM是只读寄存器,它的数据口试单向的输出端口,数据是在对FPGA现场配置时,通过配置文件一起写入存储单元的。 Lpm_ram_dq的输入/输出信号如下: 地址信号 address[]; RAM_dqo的存储单元地址; 数据输入信号DATA[] RAM_dqo的数据输入端; 数据输出信号Q[]; RAM_dqo的数据输出端; 时钟信号CLK; 读/写时钟脉冲信号; 读写信号W/R 读/写控制信号端 数据从总线端口DATA[]输入。丹输入数据和地址准备好以后,由于在inclock上的信号是地址锁存时钟,当信号上升沿到来时,地址被锁存,于是数据被写入存储单元。数据的读出控制是从A[]输入存储单元地址,在CLK信号上升沿到来时,该单元数据从Q[]输出。W/R为读/写控制端,低电平时进行读操作,高电平时进行写操作; 四 实验步骤
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值