动态规划是一种解决问题的策略,适用于具有重叠子问题和最优子结构性质的问题。
动态规划的基本思想是将原问题分解为一系列子问题,通过求解子问题的最优解来得到原问题的最优解。在求解子问题时,利用已经求解过的子问题的解来避免重复计算。
动态规划的步骤如下:
动态规划适用于求解最优化问题,例如最长公共子序列问题、0-1背包问题等。它可以显著提高计算效率,减少不必要的重复计算。
假设有n个台阶,现在要求上楼梯的方式数目。每次只能走1步或2步,问有多少种不同的方式可以到达第n个台阶?
我们定义一个dp数组,dp[i]表示到达第i个台阶的不同方式数目。
对于第i个台阶,有两种情况:
所以可以得到状态转移方程:dp[i] = dp[i-1] + dp[i-2]。
初始条件是:dp[1] = 1,dp[2] = 2。
根据状态转移方程,可以从第3个台阶开始,依次计算dp数组的值,直到计算到第n个台阶的值。
最终,dp[n]就是到达第n个台阶的不同方式数目。
#include
// 计算n个台阶有多少种上法
int countWays(int n)
{
// 创建一个长度为n的数组,用来保存计算结果
int dp[n+1];
// 基础情况
dp[1]=1;
dp[2]=2;
// 遍历计算每个台阶的上法
for (int i=3;i<=n;i++)
dp[i]=dp[i-1]+dp[i-2];
// 返回最后一个台阶的上法数量
return dp[n];
}
int main()
{
int n;
printf("请输入台阶的数量:");
scanf("%d", &n);
printf("共有%d种上法\n", countWays(n));
return 0;
}
题目描述
在一个 n×m 的只包含 0 和 1 的矩阵里找出一个不包含 0 的最大正方形,输出边长。
输入格式
输入文件第一行为两个整数 n,m(1≤n,m≤100),接下来 n 行,每行 m 个数字,用空格隔开,0 或 1。
输出格式
一个整数,最大正方形的边长。
输入输出样例
输入 #1复制
4 4
0 1 1 1
1 1 1 0
0 1 1 0
1 1 0 1
输出 #1复制
2
我们定义一个dp数组,dp[i][j]表示以节点 i , j 为右下角,可构成的最大正方形的边长。
只有a[i][j]==1时,节点i,j才能作为正方形的右下角;
对于一个已经确定的dp[i][j]=x,它表明包括节点i,j在内向上x个节点,向左x个节点扫过的正方形中所有a值都为1;
状转转移方程:if (a[i][j]==1) dp[i][j]=min(min(dp[i][j-1],dp[i-1][j]),dp[i-1][j-1])+1;
#include
using namespace std;
int main()
{
int n,m,b=0,a[101][101],dp[101][101]={0};
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
if(a[i][j]==1)
dp[i][j]=min(min(dp[i][j-1],dp[i-1][j]),dp[i-1][j-1])+1;
b=max(b,dp[i][j]);
}
printf("%d",b);
}
题目背景
很久以前,魔界大旱,水井全部干涸,温度也越来越高。为了拯救居民,夜叉族国王龙溟希望能打破神魔之井,进入人界“窃取”水灵珠,以修复大地水脉。可是六界之间皆有封印,神魔之井的封印由蜀山控制,并施有封印。龙溟作为魔界王族,习有穿行之术,可任意穿行至任何留有空隙的位置。然而封印不留有任何空隙! 龙溟无奈之下只能强行破除封印。破除封印必然消耗一定的元气。为了寻找水灵珠,龙溟必须减少体力消耗。他可以在破除封印的同时使用越行术。
题目描述
神魔之井的封印共有 n 层,每层封印都有一个坚固值。身为魔族的龙溟单独打破一层封印时需要消耗的元气为该层封印的坚固值和封印总层数 n 的平方的乘积; 但他也可以打破第 i 层到第 j 层之间的所有封印( i 输入格式 第一行包含两个正整数 n 和 t。 输出格式 仅一行,包含一个正整数,表示最小消耗元气。 输入输出样例 输入 #1复制 6 10 输出 #1复制 578 说明/提示 样例解释 先单独打破第一层,再用越行术从第二层直接打破到最后一层。 这样消耗元气 8×62+(5+5)×(5+7+9+3+5)=5788×62+(5+5)×(5+7+9+3+5)=578。 数据范围 对于 10%10% 的数据, n≤10; 由题目分出两部分 1. "单独打破一层封印时需要消耗的元气为该层封印的坚固值和封印总层数 n 的平方的乘积". 2. "打破第 i 层到第 j 层封印(i 可由两部分分别推出 题目描述 给出一个长度为 n 的序列 a,选出其中连续且非空的一段使得这段和最大。 输入格式 第一行是一个整数,表示序列的长度 n。 第二行有 n 个整数,第 i 个整数表示序列的第 i 个数字 ai。 输出格式 输出一行一个整数表示答案。 输入输出样例 输入 #1复制 7 输出 #1复制 4 说明/提示 样例 1 解释 选取 [3,5][3,5] 子段 {3,−1,2}{3,−1,2},其和为 44。 数据规模与约定 对于 40%40% 的数据,保证 n≤2×10^3。 对于 100%100% 的数据,保证 1≤n≤2×10^5,−10^4≤ai≤10^4。 暴力解法 动态规划
第二行有 n 个正整数,第 i 个数为 ai,表示第 i 层封印的坚固值。
8 5 7 9 3 5
对于 50%50% 的数据, n≤100;
对于 70%70% 的数据, n≤500;
对于 100%100% 的数据, n≤1000,ai(1≤i≤n),t≤20000。1.dp[j]=min(dp[j],dp[j-1]+a[j]*n*n);
2.if(a[j]+a[i]<=t) dp[j]=min(dp[j],dp[i-1]+(a[j]+a[i])*(f[j]-f[i-1]));//i是枚举的点
#include
P1115 最大子段和
2 -4 3 -1 2 -4 3
#include
#include