【C++】我要学会动态规划--dp问题!!

目录

P1255 数楼梯 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P1255

P1002 [NOIP2002 普及组] 过河卒 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

P1044 [NOIP2003 普及组] 栈 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P1044

P1028 [NOIP2001 普及组] 数的计算 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P1028

P1928 外星密码 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P1928


大任务 分成 小任务

动态规划        Dynamic programming,简称DP

分治策略


例如:

for(int i=3 ;i <=N;i++)
	f[i] = f[i-2]+f[i-1];
f[N].print();
return 0;

P1255 数楼梯 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P1255

忘了一道最典的题,这是后加的,建议从第二题开始(

w,随手一写RE,WA了(60分,正好及格,也算AC)

 错误代码

#include <bits/stdc++.h>
using namespace std;
int n;
long long dp[5000]={1,1,2};
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin>>n;
	for(int i=3;i<=n;i++){  //<=n 怎么又忘了
		for(int j=i-2;j<i;j++)
			dp[i]+=dp[j];
	}
	cout<<dp[n];
	return 0;
}

 高精度 打扰了  第7个测试点是500

输出:225591516161936330872512695036072072046011324913758190588638866418474627738686883405015987052796968498626 爆

#include <bits/stdc++.h>
using namespace std;
int n,f[5010][5010],len;
void jiafa(int k)//高精加法
{
	for(int i=1; i<=len; i++)//两数相加
	    f[k][i]=f[k-1][i]+f[k-2][i];
	for(int i=1; i<=len; i++)//进位
		if(f[k][i]>=10)
		{
			f[k][i+1]+=f[k][i]/10;
			f[k][i]%=10;
			if(f[k][len+1]>0)len++;
		}
}
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin>>n;
		len=1;
		f[1][1]=1;//预处理
		f[2][1]=2;//预处理
		for(int i=3; i<=n; i++)//开始计算
		    jiafa(i);
		for(int i=len; i>=1; i--)//输出
		    cout<<f[n][i];
		return 0;
}

1e8 没TLE(不对,我为何如此惧怕TLE) 


P1002 [NOIP2002 普及组] 过河卒 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

P155

假设先没有🐎

寻找初始条件 :向右 或 向左移动

寻找递推式

	f[1,1]=f[0,1]+f[1,0]; //0,0到1,1的方法总数 --f[1,1]

	f[i,j]=f[i-1,j]+f[i,j-1];    //推

有了递推式,有了初始条件,就可以求出完整的f数组的值了。
特别求出马控制的点。

#include <bits/stdc++.h>
using namespace std;
long long f[22][22];
int ctrl[22][22],n,m,hx,hy;
int dict[9][2]={{0,0},{-1,-2},{1,-2},{-1,2},{1,2},{-2,-1},{-2,1},{2,-1},{2,1}};//马点
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin>>n>>m>>hx>>hy;  //输入要到的点(n,m) &马(hx,hy)
	for(int i=0;i<9;i++)
		if(hx+dict[i][0]>=0&&hx+dict[i][0]<=n
		&&hy+dict[i][1]>=0&&hy+dict[i][1]<=m)// 如果不在地图内 忽略
			ctrl[hx+dict[i][0]][hy+dict[i][1]] =1;//马控制的具体点
	f[0][0]=1-ctrl[0][0];   //起始点 如果被马控制 直接GG 甚至可加
	/*
	if(!f[0][0]) {cout<<0; return 0;}
	*/
	for(int i=0;i<=n;i++)
		for(int j=0;j<=m;j++){
			if(ctrl[i][j]) continue; //若为控制点 跳过 默认为0
			if(i!=0) f[i][j]+=f[i-1][j];    //x
			if(j!=0) f[i][j]+=f[i][j-1];    //y
		}
		
	cout<<f[n][m];  //输出,			没想到我也有烦死了的一天
	return 0;
}

实在看不了我的代码屎山可以看官方(借鉴


P1044 [NOIP2003 普及组] 栈 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P1044

一共N个球,假设i个元素有h[i]出球方式 , 第k个小球 算前面的小球

递推式:h(n)= h(0)*h(n-1) + h(1)*h(n-2) ++ h(n-1)*h(0)       ( 看得像C_{n}^{i}

#include <bits/stdc++.h>
using namespace std;
long long h[20]={1,1};
int n;
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin>>n;
	//h[0]=1,h[1]=1;  改成上面了 h[20]={1,1}; 在声明时就能赋值...

	for(int i=2;i<=n;i++)   //<=n,取到n 只知道h[0],h[1] 循环求h[n]
		for(int j=0;j<i;j++)
   			h[i] += h[j] *h[i-j-1]; //i-j-1

	cout<<h[n]; //n==1时 本来有值,所以for循环pass也没问题
	return 0;
}

P1028 [NOIP2001 普及组] 数的计算 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P1028

简单

#include <bits/stdc++.h>
using namespace std;
int n;
long long h[1000]={1,1,2};  //大 占用的又不是我的空间
int main()
{

	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin>>n;
	for(int i=3;i<=n;i++){
		for(int j=0;j<=i/2;j++)
		//2层循环  把i/2 改成i 都不会TLE 耗得又不是我的算力(^U^)ノ
		//(1000-3+1)*(1000-3) 连1e6都不够 一秒1e8(/▽\)
			h[i]+=h[j];
	}
	cout<<h[n];
	return 0;
}

参考代码都比我麻烦  --(超时?)

 顺便复习一下memset

#include <iostream>
#include <cstring>

int main() {
    char str[10];

    memset(str, 'A', sizeof(str) - 1);
    str[sizeof(str) - 1] = '\0';

    std::cout << str << std::endl;

    return 0;
}

输出结果为:AAAAAAAAA。(9个A)在这个例子中,memset(str, 'A', sizeof(str) - 1) 将字符数组 str 的每个字节都设置为 'A',然后在末尾添加了一个空字符 '\0',以确保字符串的终止。

需要注意的是,C++提供了更安全和类型友好的初始化和赋值方式,如使用构造函数、循环或 std::fill 等。因此,在C++中使用 memset 应该谨慎,尤其是当处理非字符类型的数组时,以避免类型不匹配或对象构造/析构的问题。


P1928 外星密码 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P1928

递归

#include <bits/stdc++.h>
using namespace std;
string  expand(){
	string  s ="",X;
	char c; int D;
	while(cin>>c){
		if(c =='['){        //[
			cin>>D;
			X= expand();
			while(D--){
				s+=X;
			}
		}
		else if(c==']'){    //]
			return s;
		}
		else s +=c;
	}
	return s;//循环结束,在无[]时候
}
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cout<<expand();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值