动态规划与应用
动态规划
最大连续子序列和
基本求解方法
方法一
dp[i] 表示从A[1]到A[i]中的连续子序列的最大和
最终的最大连续子序列和 = dp[num]
#include<iostream>
using namespace std;
const int N = 10000;
int A[N];
int dp[N];
int main()
{
int num = 6;
for (int i = 1; i <= num; i++)
cin >> A[i];
int temp = -999999;
int sum = 0;
for (int i = num; i >= 1; i--)
{
sum += A[i];
if (sum > temp)
temp = sum;
dp[i] = temp;
if (sum < 0)
sum = 0;
}
printf("%d", dp[1]);
system("pause");
return 0;
}
方法二
dp[i] 表示以A[i]结尾的连续序列的最大和
求出整个dp数组,然后遍历整个数组找到最大值就是最大连续子序列和
3个动归要点:
状态变量:dp[i]
边界:dp[1] = A[1]
状态转移方程: dp[i] = max(A[i],dp[i-1]+A[i])
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 10000;
int A[N];
int dp[N];
int main()
{
int num = 6;
for (int i = 1; i <= num; i++)
cin >> A[i];
//边界
dp[1] = A[1];
for (int i = 2; i <=num; i++)
{
dp[i] = max(dp[i - 1] + A[i], A[i]);
}
int k = dp[1];
for (int i = 2; i <=num ; i++)
{
if (dp[i] > k)
k = dp[i];
}
printf("%d",k);
system("pause");
return 0;
}
例1 Maximum sum
#include<iostream>
using namespace std;
const int N = 100010;
int A[N];
int dpr[N]; //从右向左dp,求出连续子序列的最大和。dp[i]表示从A[1]到A[i]中连续子序列的最大和
int dpl[N]; //从左向右dp,求出连续子序列的最大和。dp[i]表示从A[i]到A[N]中连续子序列的最大和
int main()
{
int T,k;
scanf("%d", &T);
while (T--)
{
scanf("%d", &k);
//将整个序列读入
for (int i = 1; i <= k; i++)
cin >> A[i];
//求解dpr[i]
int sum = 0;
int temp = -9999999;
for (int i = 1; i <= k; i++)
{
sum += A[i];
if (sum > temp)
temp = sum;
dpr[i] = temp;
if (sum < 0)
sum = 0;
}
sum = 0; temp = -9999999;
//求解dpl[i]
for (int i = k; i >=1; i--)
{
sum += A[i];
if (sum > temp)
temp = sum;
dpl[i] = temp;
if (sum < 0)
sum = 0;
}
int MaxSum = -9999999;
for (int i = 1; i < k; i++)
{
int t = dpr[i] + dpl[i + 1];
if (MaxSum < t)
MaxSum = t;
}
cout << MaxSum << endl;
}
system("pause");
return 0;
}
最佳加法表达式
例题
POJ 4103 踩方格
思路:ways(i,j,n): 从结点(i, j)开始走n步的方法数
ways(i,j,n) = ways(i,j-1,n-1) + ways(i,j+1,n-1) + ways(i+1,j,n-1)
使用数组vis[i][j] 标记结点(i, j)是否被走过
Tips:
- 先判断 n 是否为0,再将结点(i, j)进行标记
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int vis[50][50];
int ways(int i, int j, int n)
{
if (n == 0)
{
return 1;
}
int num = 0;
if (!vis[i][j - 1])
{
vis[i][j - 1] = 1;
num += ways(i, j - 1, n - 1);
vis[i][j - 1] = 0;
}
if (!vis[i][j + 1])
{
vis[i][j + 1] = 1;
num += ways(i, j + 1, n - 1);
vis[i][j + 1] = 0;
}
if (!vis[i+1][j])
{
vis[i + 1][j] = 1;
num += ways(i+1, j, n - 1);
vis[i + 1][j] = 0;
}
return num;
}
int main()
{
int n;
cin >> n;
memset(vis, 0, sizeof(vis));
vis[0][25] = 1;
cout << ways(0, 25, n) << endl;
return 0;
}