关于记忆化搜索加DP的理解

对于DP的初识

第一次接触DP是在洛谷的过河卒这道题:https://www.luogu.com.cn/problem/P1002。
一开始想用DFS去解,//未完待续

神奇的dp小题

https://www.lanqiao.cn/problems/17104/learning/?page=1&first_category_id=1&second_category_id=3&name=子2023
蓝桥杯的一道小题,完全没想到是一道dp题,只想到了暴力方法,暴力方法我的电脑跑要一分钟,不知道蓝桥杯的要几分钟,但是逻辑是对的就一定能跑出来

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
string s;

void solv()
{
    LL res = 0;
    for(int i = 0; i < s.size(); i ++)
    {
        if(s[i] != '2')
            continue;
        for(int j = i + 1; j < s.size(); j ++)
        {
            if(s[j] != '0')
                continue;
            for(int k = j + 1; k < s.size(); k ++)
            {
                if(s[k] != '2')
                    continue;
                for(int l = k + 1; l < s.size(); l ++)
                {
                    if(s[l] != '3')
                        continue;
                    if(s[i] == '2' && s[j] == '0' && s[k] == '2' && s[l] == '3')
                        res ++;
                }
            }    
        }
    }
    cout << res << endl;
}

int main()
{
    for(int j = 1; j <= 2023; j ++)
    {
        string p = to_string(j);
        for(int i = 0; i < p.size(); i ++)
        {
            if(p[i] == '2' || p[i] == '0' || p[i] == '3')
            {
                s += p[i];
            }
        }
    }
//    cout << s.size() << endl;
//    cout << s << endl;
    solv();
    return 0;
}
这是暴力代码,下面考虑dp 考虑状态表示,只需一维,dp【i】表示前i个数字已找到的个数,例如dp【2】表示已找到“20”序列的个数,状态转移为dp【i】+= dp【i - 1】,例如:20232023,当遍历到第一个0时,只能出现一个“20”序列,所以dp【2】= 1,当遍历到第二个0的时候,dp【2】+= dp【1】,此时dp【1】为3,因为有3个2,而第二个0可与这三个2都产生“20”的序列所以此时dp【2】= 4.
点击查看代码
#include <iostream>
#include <cstring>
using namespace std;

char s[10000]; // 存储最终结果的字符串
char v[5];     // 临时存储每一位数字

int main() {
    int m = 0; // 当前字符串的长度
    for (int i = 1; i <= 2023; ++i) {
        int z = 0; // 当前数字的位数
        int w = i; // 当前数字
        while (w > 0) {
            int x = w % 10; // 获取当前数字的最后一位
            v[z] = '0' + x; // 将数字转换为字符形式
            w = w / 10;     // 去掉最后一位
            z++;
        }
        // 将数字的每一位逆序存储到s中
        for (int j = z - 1; j >= 0; --j) {
            s[m++] = v[j];
        }
    }
    // 添加字符串结束符
    s[m] = '\0';
    // 输出结果
    //cout << s << endl;
    int n = 0;
    long long dp[4] = {0,0,0,0};
    for (int i = 0; i < strlen(s); ++i)
    {
    	if (s[i] == '2')
		{
			dp[0] += 1;
			dp[2] += dp[1];
		} 
		if (s[i] == '0')
		{
			dp[1] += dp[0];
		}
		if (s[i] == '3')
		{
			dp[3] += dp[2];
		}
	}
	cout << dp[3] ;
    return 0;
}
#蓝桥杯16届 水质检测 这道题看起来很像贪心,也确实可以用贪心去做,但是如果分类讨论分的不清楚的话,只能拿部分分
posted @ 2025-04-04 23:03  hendry_0702  阅读(19)  评论(0)    收藏  举报