一、概念
动态规划策略,一种分治策略。和贪婪策略一样,通常是用来解决最优解问题。分治故名就是将问题分解为几个子问题来解决,动态规划的特点就是分解的子问题中(子问题又可以分解成子问题)每次选择选择最优解。
动态规划主要的特点是在做决定前她知道所有子问题的信息。
动态规划的两个重要要素是:1)最优子结构。2)重叠子问题。
1)最优子结构,这是采取动态规划策略解最优化问题后要做的第一步。所谓最优化子结构是说若问题的一个最优解中包含了子问题的最优解,则该问题具有最优子结构。这个是我们采取动态规划的一个充分条件(当然这个条件也满足贪婪策略),问题出现这个条件就可以考虑采取动态规划。
一般要考虑的因素是:
1.1)最优解里需要解决的子问题数量有多少?
1.2)在判断使用那些子问题时需要进行多少选择?
2)重叠子问题,是指在递归解决方案中,若产生了大量的相同子问题,那么相同的子问题就会被重复计算很多次,这样算法的效率损耗就很大。这个要素是动态规划的优势所在,可以说动态规划就是为解决这种问题而生的(实际上,有记忆的递归算法也可以做到类似的算法改进).
二、解题策略
一般解题的思路为:
1)证明问题的解决方案中包括一个选择,选择之后将留下一个或多个子问题
2)设计子问题的递归描述方式(一般会出现递归公式又称转移方程,这个是解题和算法的关键)
3)证明对原问题的最优解里包括对所有子问题的最优解
4)证明子问题之间有重叠
可以看出1、3、4是为了使得子问题的构建能符合动态规划策略,他们的目的都是为了他构建一个合理恰当的子问题而服务的。但是不同问题构建子问题的思路不尽相同。除了要考虑1.1、1.2的问题外,通常有个比较有效的经验,就是尽量使得这个子问题简单,然后在需要的时候去扩充她. (原文地址)
/*
Name: hdu 2084
Copyright:
Author:
Date: 06/03/15 09:04
Description: 动态规划
*/
#include<cstdio>
#include<iostream>
using namespace std;
int a[105][105];
int f[105];
int max(int a, int b)
{
return a > b ? a : b;
}
int main()
{
//freopen("E:\input.txt", "r",stdin);
int k;
scanf("%d", &k);
int n, i, j;
while (k--)
{
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
for (j = 1; j <= i; j++)
{
scanf("%d", &a[i][j]);
}
}
for (j = 1; j <= n; j++)
{
f[j] = a[n][j]; //自底向上
}
for (i = n - 1; i >= 0; i--)
{
for (j = 1; j <= i; j++)
{
f[j] = max(f[j], f[j + 1]) + a[i][j]; //动态转移方程
}
}
printf("%d\n", f[1]);
}
return 0;
}
hdu 1176 免费馅饼
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
int f[100005][13];
int a[100005][13];
int max(int a, int b, int c)
{
if (a < b)
{
a = b;
}
if (a < c)
{
a = c;
}
return a;
}
int main()
{
// freopen("E:\input.txt", "r", stdin);
int n, location, time;
while (scanf("%d",&n)!=EOF&&n)
{
int i, j;
int maxtime = 0;
memset(f, 0, sizeof(f));
memset(a, 0, sizeof(a));
for (i = 1; i <= n; i++)
{
scanf("%d%d", &location, &time);
a[time][location + 1]++;
if (time > maxtime)
{
maxtime = time;
}
}
for (i = 1; i <= 11; i++)
{
f[maxtime][i] = a[maxtime][i];
}
for (i = maxtime - 1; i >= 0; i--)
{
for (j = 1; j <= 11; j++)
{
f[i][j] = max(f[i + 1][j - 1] + a[i][j], f[i + 1][j] + a[i][j], f[i + 1][j + 1] + a[i][j]) ;
}
}
printf("%d\n", f[0][6]);
}
return 0;
}
<span style="font-size:18px;">#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
int a[22][12];
int f[22][12];
int main()
{
// freopen("E:\input.txt", "r", stdin);
int n, k, i, j, min;
while ((scanf("%d%d", &n, &k)) != EOF)
{
memset(a, 0, sizeof(a));
memset(f, 0, sizeof(f));
for (i = 1; i <= n; i ++)
{
for (j = 1; j <= k; j++)
{
scanf("%d", &a[i][j]);
}
}
for (i = 1; i <= k; i++)
{
f[n][i] = 0;
}
for (i = n - 1; i >= 1; i--)
{
for (j = 1; j <= k; j++)
{
// int t = 1;
f[i][j] = abs(a[i][j] - a[i + 1][1]) + f[i + 1][1];
for (int t = 2; t <= k; t++) //找最小的值
{
int temp = abs(a[i + 1][t] - a[i][j]) + f[i + 1][t];
if (temp < f[i][j])
{
f[i][j] = temp;
}
}
}
}
min = f[1][1];
for (i = 2; i <= k; i++)
{
if (f[1][i] < min)
{
min = f[1][i];
}
}
printf("%d\n", min);
}
return 0;
}</span>