欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

c++動態(tài)規(guī)劃經(jīng)典算法

 更新時間:2021年08月17日 11:02:29   作者:靜篤歸心方得平和心氣  
動態(tài)規(guī)劃算法通常用于求解具有某種最優(yōu)性質(zhì)的問題。本文主要介紹了c++動態(tài)規(guī)劃經(jīng)典算法,具有一定的參考價值,感興趣的小伙伴們可以參考一下

基本思想

         動態(tài)規(guī)劃算法通常用于求解具有某種最優(yōu)性質(zhì)的問題。在這類問題中,可能會有許多可行解。每一個解都對應(yīng)于一個值,我們希望找到具有最優(yōu)值的解。動態(tài)規(guī)劃算法與分治法類似,其基本思想也是將待求解問題分解成若干個子問題,先求解子問題,然后從這些子問題的解得到原問題的解。與分治法不同的是,適合于用動態(tài)規(guī)劃求解的問題,經(jīng)分解得到子問題往往不是互相獨立的。若用分治法來解這類問題,則分解得到的子問題數(shù)目太多,有些子問題被重復(fù)計算了很多次。如果我們能夠保存已解決的子問題的答案,而在需要時再找出已求得的答案,這樣就可以避免大量的重復(fù)計算,節(jié)省時間。我們可以用一個表來記錄所有已解的子問題的答案。不管該子問題以后是否被用到,只要它被計算過,就將其結(jié)果填入表中。這就是動態(tài)規(guī)劃法的基本思路。具體的動態(tài)規(guī)劃算法多種多樣,但它們具有相同的填表格式。

重要分析問題方法

        動態(tài)規(guī)劃算法跟數(shù)組有著密切的關(guān)系,因此推薦大家在分析動態(tài)規(guī)劃的算法時畫一張表格(建議使用excel)分析解決問題往往能夠事半功倍。

動態(tài)規(guī)劃算法實例

1、臺階問題

 問題描述:有10級臺階,一個人每次上一級或者兩級,問有多少種走完10級臺階的方法。

結(jié)合表格分析問題,每個子問題都只跟臺階這個變量相關(guān),可以畫出一個一維表格進行分析。

  1 2 3 4 5 6 7 8 9 10
走法 1 2 3 5 8 13 21 34 55 89

分析邊界條件:對于每個臺階每次上一級或者兩級,當(dāng)臺階數(shù)為1時走法為1(即走一級即畢)為2時走法為2(走兩次一級和走一次二級)。

分析遞歸關(guān)系:對于任一臺階都可以分為通過兩級或者一階到達。

      

終于,在有了上述兩個條件之后,問題輕易得到了求解。(結(jié)合表格分析的手段到這里還沒有完全發(fā)揮出它該有的優(yōu)勢,大家拭目以待)

臺階問題基于c++的代碼實現(xiàn):

// ConsoleApplication2.cpp : 定義控制臺應(yīng)用程序的入口點。
//
//臺階問題:有一座高度是10級臺階的樓梯,從下往上走,每跨一步只能向上1級或者2級臺階。要求用程序來求出一共有多少種走法。
#include "stdafx.h"
#include <iostream>
using namespace std;
int getResultByDP(int n)//自底向上的問題解法
{
	if (n<1)
	{
		return 0;
	}
	if (n==1)
	{
		return 1;
	}
	if (n==2)
	{
		return 2;
	}
	int a = 1;//從兩個遞歸基開始
	int b = 2;
	int temp = 0;
	for (int i = 3; i < n + 1; i++)
	{
		temp = a + b;
		a = b;
		b = temp;
	}
	return temp;
}
int _tmain(int argc, _TCHAR* argv[])
{
	cout << getResultByDP(10);
	system("pause");
	return 0;
}

2、從矩陣左上角走到右下角最短路徑問題

問題描述:給定一個矩陣m,從左上角開始每次只能向右走或者向下走,最后達到右下角的位置,路徑中所有數(shù)字累加起來就是路徑和,返回所有路徑的最小路徑和,如果給定的m如下,那么路徑1,3,1,0,6,1,0就是最小路徑和,返回12.

1 3 5 9

8 1 3 4

5 0 6 1

8 8 4 0

矩陣從左上角走到右下角
  0 1 2 3 4
0 0 0 0 0 0
1 0 1 3 5 9
2 0 8 1 3 5
3 0 5 0 6 1
4 0 8 8 4 0
           
  0 1 2 3 4
0 0 0 0 0 0
1 0 1 4 9 18
2 0 9 5 8 13
3 0 14 5 11 12
4 0 22 13 15 12

邊界條件分析:由問題知道對于任一矩陣中的元素而言,上次位置或者是在該元素的坐標(biāo)或者上邊。那么當(dāng)一些元素沒有左邊或者上邊時應(yīng)該怎么做呢?不妨就說的更為具體一些吧,如上圖的表格所示當(dāng)x(表示行下標(biāo))等于1,和y(表示列下標(biāo))等于1時正好是對應(yīng)沒有上邊元素和沒有左邊元素的情況。對于只有左邊元素的值array[x][y]=array[x][y-1]+m[x][y],對于只有上邊元素:array[x][y]=array[x-1][y]+m[x][y](array為下面統(tǒng)計問題結(jié)果的二維數(shù)組,m為包含輸入矩陣信息的二維數(shù)組)。

遞歸公式:對于平凡的子問題而言 (推導(dǎo)遞歸公式時刻意的考察array[x][y]和array[x-1][y]與array[x][y-1]的實際關(guān)系)

對于此問題而言:arry[x][y]=min(array[x-1][y],array[x][y-1])+m[x][y]

以下是該問題基于c++的代碼實現(xiàn):

//給定一個矩陣m,從左上角開始每次只能向右走或者向下走,最后達到右下角的位置,路徑中所有數(shù)字累加起來就是路徑和,返回所有路徑的最小路徑和,如果給定的m如下,那么路徑1,3,1,0,6,1,0就是最小路徑和,返回12.
#include "stdafx.h"
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
int const x_length=5, y_length=5;
int m[x_length][y_length] = {
	0, 0, 0, 0, 0,
	0, 1, 3, 5, 9,
	0, 8, 1, 3, 5,
	0, 5, 0, 6, 1,
	0, 8, 8, 4, 0
};
int minDis() //m二級指針(可以是一個二維數(shù)組)
{
	int dp[4 + 1][4 + 1];
	//---------初始化邊界條件-----------------
	for (size_t i = 0; i < x_length; i++)
	{
		dp[i][0] = 0;
	}
	for (size_t j = 0; j < y_length; j++)
	{
		dp[0][j] = 0;
	}
	//-------------------------------------------
	for (size_t i = 1; i < x_length; i++)
	{
		for (size_t j= 1; j < y_length; j++)
		{
			if (i == 1)
			{
				dp[i][j] = dp[i][j - 1] + m[i][j];
			}
			else if (j == 1)
			{
				dp[i][j] = dp[i - 1][j] + m[i][j];
			}
			else
			{
				int temp1 = dp[i - 1][j] + m[i][j];
				int temp2 = dp[i][j - 1] + m[i][j];
				dp[i][j] = min(temp1, temp2);
			}			
		}
	}
	return dp[x_length - 1][y_length - 1];
}
int _tmain(int argc, _TCHAR* argv[])
{
	cout << "最右下角的最短路徑為:" << minDis();
	system("pause");
	return 0;
}

3、最大子數(shù)組問題

問題描述:給定數(shù)組arr,返回arr的最長遞增子序列的長度,比如arr=[2,1,5,3,6,4,8,9,7],最長遞增子序列為[1,3,4,8,9]返回其長度為5,由于該問題中總要把當(dāng)前元素和在他之前的進行分析,我們也是借助表格來直觀的分析該問題。

    2 4 5 3 1    
    0 1 2 3 4 5 6
2 0              
4 1              
5 2              
3 3              
1 4              
                 
0 1 2 3 4        
1 2 3 2 1        

邊界條件:顯然對于第一個數(shù)而言有dp[0]=1(dp表示存放結(jié)果的數(shù)組)

遞歸公式:首先生成dp[n]的數(shù)組,dp[i]表示以必須arr[i]這個數(shù)結(jié)束的情況下產(chǎn)生的最大遞增子序列的長度。對于第一個數(shù)來說,很明顯dp[0]為1,當(dāng)我們計算dp[i]的時候,我們?nèi)タ疾靑位置之前的所有位置,找到i位置之前的最大的dp值,記為dp[j](0=<j<i),dp[j]代表以arr[j]結(jié)尾的最長遞增序列,而dp[j]又是之前計算過的最大的那個值,我們在來判斷arr[i]是否大于arr[j],如果大于dp[i]=dp[j]+1.計算完dp之后,我們找出dp中的最大值,即為這個串的最長遞增序列。

該問題基于c++的代碼實現(xiàn):

//給定數(shù)組arr,返回arr的最長遞增子序列的長度,比如arr=[2,1,5,3,6,4,8,9,7],最長遞增子序列為[1,3,4,8,9]返回其長度為5.
#include "stdafx.h"
#include <string>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int dp[5] = {};
int _tmain(int argc, _TCHAR* argv[])
{
 int arr[5] = { 2, 4, 5, 3, 1 };
 dp[0] = 1;
 const int oo = 0;
 for (int i = 1; i<5; i++){
  int _max = oo;
  for (int j = 0; j<i; j++)
   if (dp[j]>_max && arr[i]>arr[j])
    _max = dp[j];
  dp[i] = _max + 1;
 }
 int maxlist = 0;
 for (int i = 0; i < 5; i++)
  if (dp[i] > maxlist)
   maxlist = dp[i];
 cout << maxlist << endl;
 system("pause");
 return 0;
}

4、最長公共子序列

問題描述:給定兩個字符串str1和str2,返回兩個字符串的最長公共子序列,例如:str1="1A2C3D4B56",str2="B1D23CA45B6A","123456"和"12C4B6"都是最長公共子序列,返回哪一個都行。

問題分析:首先生成dp[n]的數(shù)組,dp[i]表示以必須arr[i]這個數(shù)結(jié)束的情況下產(chǎn)生的最大遞增子序列的長度。對于第一個數(shù)來說,很明顯dp[0]為1,當(dāng)我們計算dp[i]的時候,我們?nèi)タ疾靑位置之前的所有位置,找到i位置之前的最大的dp值,記為dp[j](0=<j<i),dp[j]代表以arr[j]結(jié)尾的最長遞增序列,而dp[j]又是之前計算過的最大的那個值,我們在來判斷arr[i]是否大于arr[j],如果大于dp[i]=dp[j]+1.計算完dp之后,我們找出dp中的最大值,即為這個串的最長遞增序列。

    B D C A B A  
    0 1 2 3 4 5  
A 0 0 0 0 0 0 0 0
B 1 0 0 0 0 1 1 1
C 2 0 1 1 1 1 2 2
B 3 0 1 1 2 2 2 2
D 4 0 1 1 2 2 3 3
A 5 0 1 2 2 2 3 3
B 6 0 1 2 2 3 3 4
  7 0 1 2 2 3 4 4
                 
    B D C A B A  
    0 1 2 3 4 5  
A 0 -2 -2 -2 -2 -2 -2 -2
B 1 -2 -1 -1 -1 0 1 0
C 2 -2 0 1 1 -1 0 1
B 3 -2 -1 -1 0 1 -1 -1
D 4 -2 0 -1 -1 -1 0 1
A 5 -2 -1 0 -1 -1 -1 -1
B 6 -2 -1 -1 -1 0 -1 0
  7 -2 0 -1 -1 -1 0 -1

該問題基于c++代碼實現(xiàn):

//輸入為兩個長度不為零的字符串,輸出這兩個字符串的最大公共子序列
#include "stdafx.h"
#include <string>
#include <iostream>
#ifndef MAX
#define MAX(X,Y) ((X>=Y)? X:Y)
#endif
using namespace std;
int **Lcs_length(string X, string Y, int **B)
{
 int x_len = X.length();
 int y_len = Y.length();
 int **C = new int *[x_len + 1];
 for (int i = 0; i <= x_len; i++)
 {
  C[i] = new int[y_len + 1];        //定義一個存放最優(yōu)解的值的表;
 }
 for (int i = 0; i <= x_len; i++)
 {
  C[i][0] = 0;
  B[i][0] = -2;                     //-2表示沒有方向
 }
 for (int j = 0; j <= y_len; j++)
 {
  C[0][j] = 0;
  B[0][j] = -2;
 }
 for (int i = 1; i <= x_len; i++)
 {
  for (int j = 1; j <= y_len; j++)
  {
 
   if (X[i - 1] == Y[j - 1])
   {
    C[i][j] = C[i - 1][j - 1] + 1;
 
    B[i][j] = 0;             //0表示斜向左上
   }
   else
   {
    if (C[i - 1][j] >= C[i][j - 1])
    {
     C[i][j] = C[i - 1][j];
     B[i][j] = -1;       //-1表示豎直向上;
    }
    else
    {
     C[i][j] = C[i][j - 1];
     B[i][j] = 1;        //1表示橫向左
    }
   }
 
  }
 }
 return C;
}
 
void OutPutLCS(int **B, string X, int str1_len, int str2_len)
{
 if (str1_len == 0 || str2_len == 0)
 {
  return;
 }
 if (B[str1_len][str2_len] == 0)   //箭頭斜向左上
 {
  OutPutLCS(B, X, str1_len - 1, str2_len - 1);
  cout << X[str1_len - 1] << endl;
 }
 else if (B[str1_len][str2_len] == -1)
 {
  OutPutLCS(B, X, str1_len - 1, str2_len);
 }
 else
 {
  OutPutLCS(B, X, str1_len, str2_len - 1);
 }
}
 
int _tmain(int argc, _TCHAR* argv[])
{
 string X = "ABCBDAB";
 string Y = "BDCABA";
 
 int x_len = X.length();
 int y_len = Y.length();
 
 int **C;//定義一個二維數(shù)組
 
 int **B = new int *[x_len + 1];
 for (int i = 0; i <= x_len; i++)
 {
  B[i] = new int[y_len + 1];
 }
 C = Lcs_length(X, Y, B);
 for (int i = 0; i <= x_len; i++)
 {
  for (int j = 0; j <= y_len; j++)
  {
   cout << C[i][j] << " ";
  }
  cout << endl;
 }
 cout << endl;
 for (int i = 0; i <= x_len; i++)
 {
  for (int j = 0; j <= y_len; j++)
  {
   cout << B[i][j] << " ";
  }
  cout << endl;
 }
 OutPutLCS(B, X, x_len, y_len);//構(gòu)造最優(yōu)解
 system("pause");
 return 0;
}

到此這篇關(guān)于c++動態(tài)規(guī)劃經(jīng)典算法的文章就介紹到這了,更多相關(guān)c++動態(tài)規(guī)劃內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言關(guān)鍵字union的定義和使用詳解

    C語言關(guān)鍵字union的定義和使用詳解

    這篇文章主要介紹了C語言關(guān)鍵字union的定義和使用詳解,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-02-02
  • C語言中建立和刪除文件連接的相關(guān)函數(shù)講解

    C語言中建立和刪除文件連接的相關(guān)函數(shù)講解

    這篇文章主要介紹了C語言中建立和刪除文件連接的相關(guān)函數(shù)講解,分別為link和unlink函數(shù)的使用,需要的朋友可以參考下
    2015-09-09
  • C++ class和struct到底有什么區(qū)別詳解

    C++ class和struct到底有什么區(qū)別詳解

    這篇文章主要介紹了C++ class和struct到底有什么區(qū)別詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • vc6.0中c語言控制臺程序中的定時技術(shù)(定時器)

    vc6.0中c語言控制臺程序中的定時技術(shù)(定時器)

    這篇文章主要介紹了vc6.0中c語言控制臺程序中的定時技術(shù)(定時器),需要的朋友可以參考下
    2014-04-04
  • 一文讀懂C++中指針和內(nèi)存分配

    一文讀懂C++中指針和內(nèi)存分配

    我們知道聲明的所有變量在內(nèi)存中都有一個特定的地址。聲明一個指針變量來指向內(nèi)存中的這些地址,這篇文章主要介紹了C++中指針和內(nèi)存分配,需要的朋友參考下吧
    2021-06-06
  • C語言超細致講解函數(shù)遞歸

    C語言超細致講解函數(shù)遞歸

    程序調(diào)???的編程技巧稱為遞歸?recursion)函數(shù)??調(diào)???就是遞歸,你也可以理解成是?種嵌套結(jié)構(gòu),但遞歸分為倆部分,第?是“遞”,進?嵌套結(jié)構(gòu)。第?是”歸“,最終會?步?步返回。第?次接觸遞歸都會很懵,慢慢理解這個過程就明?了
    2022-05-05
  • 使用VS2022開發(fā)在線遠程編譯部署的C++程序(圖文詳解)

    使用VS2022開發(fā)在線遠程編譯部署的C++程序(圖文詳解)

    這篇文章主要介紹了使用VS2022開發(fā)可以在線遠程編譯部署的C++程序,本文分步驟通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-12-12
  • C語言詳細講解多維數(shù)組與多維指針

    C語言詳細講解多維數(shù)組與多維指針

    C 語言中的多維數(shù)組(multidimensional array)其實就是元素為數(shù)組的數(shù)組。多維指針根據(jù)聲明的維數(shù)需要進行多次地址轉(zhuǎn)換才能夠取到目標(biāo)數(shù)據(jù)。但指針作為數(shù)據(jù)變量,可以多次賦值,使其成為對數(shù)組操作訪問的一大利器,所以指針和數(shù)組的結(jié)合才是重中之重
    2022-04-04
  • C++實現(xiàn)LeetCode(150.計算逆波蘭表達式)

    C++實現(xiàn)LeetCode(150.計算逆波蘭表達式)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(150.計算逆波蘭表達式),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C語言基于EasyX庫實現(xiàn)有顏色彈跳小球

    C語言基于EasyX庫實現(xiàn)有顏色彈跳小球

    這篇文章主要為大家詳細介紹了C語言基于EasyX庫實現(xiàn)有顏色彈跳小球,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01

最新評論