# 动态规划

## 分治与动态规划

动态规划将分解后的子问题理解为相互间有联系,有重叠部分，需要记忆，通常用迭代来做。

## 典型问题

### 01背包问题

```int main()
{
//int m = 120;
//int n = 5;
//vector<int> w = { 0, 40, 50, 70, 40, 20 };
//vector<int> v = { 0, 10, 25, 40, 20, 10 };

int m, n;    //m重量，n数量
while (cin >> m >> n)
{
vector<int> w(n + 1, 0);
vector<int> v(n + 1, 0);
for (int i = 1; i <= n; i++)
{
int tmp;
cin >> tmp;
w[i] = tmp;
}
for (int i = 1; i <= n; i++)
{
int tmp;
cin >> tmp;
v[i] = tmp;
}
vector< vector<int> > vec(n + 1, vector<int>(m + 1, 0));
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if (w[i] > j)
vec[i][j] = vec[i - 1][j];
else
{
int tmp1 = v[i] + vec[i - 1][j - w[i]];
int tmp2 = vec[i - 1][j];
vec[i][j] = tmp1 > tmp2 ? tmp1 : tmp2;
}
}
}
double val = vec[n][m] * 0.1;
cout << val << endl;
}

system("pause");
}```

### 最长公共子序列（不连续） LCS　　Longest Common Subsequence

cnblogs与belong，最长公共子序列为blog（cnblogs, belong），最长公共子串为lo（cnblogs, belong）

C++实现最长公共子序列和最长公共子串

``` 1 public static int lcs(String str1, String str2) {
2     int len1 = str1.length();
3     int len2 = str2.length();
4     int c[][] = new int[len1+1][len2+1];
5     for (int i = 0; i <= len1; i++) {
6         for( int j = 0; j <= len2; j++) {
7             if(i == 0 || j == 0) {
8                 c[i][j] = 0;
9             } else if (str1.charAt(i-1) == str2.charAt(j-1)) {
10                 c[i][j] = c[i-1][j-1] + 1;
11             } else {
12                 c[i][j] = max(c[i - 1][j], c[i][j - 1]);
13             }
14         }
15     }
16     return c[len1][len2];
17 }```

### 最长公共子串（连续）

``` 1 public static int lcs(String str1, String str2) {
2     int len1 = str1.length();
3     int len2 = str2.length();
4     int result = 0;     //记录最长公共子串长度
5     int c[][] = new int[len1+1][len2+1];
6     for (int i = 0; i <= len1; i++) {
7         for( int j = 0; j <= len2; j++) {
8             if(i == 0 || j == 0) {
9                 c[i][j] = 0;
10             } else if (str1.charAt(i-1) == str2.charAt(j-1)) {
11                 c[i][j] = c[i-1][j-1] + 1;
12                 result = max(c[i][j], result);
13             } else {
14                 c[i][j] = 0;
15             }
16         }
17     }
18     return result;
19 } ```

KMP算法

View Code

View Code

### 最长回文字串

P[i,j]=0表示子串[i,j]不是回文串。P[i,j]=1表示子串[i,j]是回文串。

P[i+1][j-1]&&s.at(i)==s.at(j)

``` 1 string findLongestPalindrome(string &s)
2 {
3     const int length=s.size();
4     int maxlength=0;
5     int start;
6     bool P[50][50]={false};
7     for(int i=0;i<length;i++)//初始化准备
8     {
9         P[i][i]=true;
10         if(i<length-1&&s.at(i)==s.at(i+1))
11         {
12             P[i][i+1]=true;
13             start=i;
14             maxlength=2;
15         }
16     }
17     for(int len=3;len<length;len++)//子串长度
18         for(int i=0;i<=length-len;i++)//子串起始地址
19         {
20             int j=i+len-1;//子串结束地址
21             if(P[i+1][j-1]&&s.at(i)==s.at(j))
22             {
23                 P[i][j]=true;
24                 maxlength=len;
25                 start=i;
26             }
27         }
28     if(maxlength>=2)
29         return s.substr(start,maxlength);
30     return NULL;
31 }```

### 最长递增序列

LIS[i]：表示数组前i个元素中（包括第i个），最长递增子序列的长度

LIS[i] = max{ 1, LIS[k]+1 }, 0 <= k < i, a[i]>a[k]

LIS数组的值表示前i个元素的最长子序列。i从第一个元素到最后一个元素遍历一遍，j从第一个元素到第i个元素遍历，如果第i个元素大于j，并且LIS[J] + 1比LIS[I]还大就更新，相当于把j加入到这个递增序列了

``` 1 int LIS(int a[], int length)
2 {
3     int *LIS = new int[length];
4     for(int i = 0; i < length; ++i)
5     {
6         LIS[i] = 1; //初始化默认长度
7         for(int j = 0; j < i; ++j) //前面最长的序列
8             if(a[i] > a[j] && LIS[j]+1 > LIS[i])
9                 LIS[i] = LIS[j]+1;
10     }
11     int max_lis = LIS[0];
12     for(int i = 1; i < length; ++i)
13         if(LIS[i] > max_lis)
14             max_lis = LIS[i];
15     return max_lis;  //取LIS的最大值
16 }```

## 其他问题

1.某幢大楼有100层。你手里有两颗一模一样的玻璃珠。当你拿着玻璃珠在某一层往下扔的时候，一定会有两个结果，玻璃珠碎了或者没碎。这幢大楼有个临界楼层。低于它的楼层，往下扔玻璃珠，玻璃珠不会碎，等于或高于它的楼层，扔下玻璃珠，玻璃珠一定会碎。玻璃珠碎了就不能再扔。现在让你设计一种方式，使得在该方式下，最坏的情况扔的次数比其他任何方式最坏的次数都少。也就是设计一种最有效的方式。

``` 1 /*
2 *侯凯,2014-9-15
3 *功能：100楼层抛珠问题
4 */
5 #include<iostream>
6 using namespace std;
7
8 int max(int a, int b)
9 {
10     return (a > b)? a : b;
11 }
12
13 int dp[101];
14 //N<=100;
15 int floorThr(int N)
16 {
17     for (int i = 2; i <= N; i++)
18     {
19         dp[i] = i;
20         for (int j = 1; j<i; j++)
21         {
22             int tmp = max(j, 1 + dp[i - j]);    //j的遍历相当于把每层都试一遍
23             if (tmp<dp[i])
24                 dp[i] = tmp;
25         }
26     }
27     return dp[N];
28 }
29
30 int main()
31 {
32     dp[0] = 0;
33     dp[1] = 1;
34     int dis = floorThr(100);
35     cout << dis << endl;
36     system("Pause");
37 }```

## N*N方格内的走法问题

``` 1 #include<iostream>
2 #include<vector>
3 using namespace std;
4
5 int main()
6 {
7     int n;
8     while (cin >> n)
9     {
10         vector<vector<int>> dp(n+1, vector<int>(n+1, 1));
11         for (int i = 1; i <= n;i++)
12         {
13             for (int j = 1; j <= n;j++)
14             {
15                 dp[i][j] = dp[i][j - 1] + dp[i - 1][j];
16             }
17         }
18         cout << dp[n][n] << endl;
19     }
20 }```

http://www.cnblogs.com/wuyuegb2312/p/3281264.html#q1a1

http://www.cnblogs.com/luxiaoxun/archive/2012/11/15/2771605.html

原文作者：动态规划
原文地址: https://blog.csdn.net/yuxin6866/article/details/52507623
本文转自网络文章，转载此文章仅为分享知识，如有侵权，请联系博主进行删除。