天天看點

動态規劃之經典例題

1、三角數塔問題

設有一個三角形的數塔,頂點為根結點,每個結點有一個整數值。從頂點出發,可以向左走或向右走,如圖所示:

動态規劃之經典例題

要求從根結點開始,請找出一條路徑,使路徑之和最大,隻要輸出路徑的和。

【代碼】

//

// 例題1 三角數字塔問題 //

#include <stdio.h>

#include <stdlib.h>

#define MAXN 101

int n,d[MAXN][MAXN];

int a[MAXN][MAXN];

void fnRecursive(int,int);

//遞推方法函數聲明

int fnMemorySearch(int,int);

//記憶化搜尋函數聲明

int main()

{

int i,j;

printf("輸入三角形的行數n(n=1-100):\n");

scanf("%d",&n);

printf("按行輸入數字三角形上的數(1-100):\n");

for(i=1; i<=n; i++)

for(j=1; j<=i; j++)

scanf("%d",&a[i][j]);

d[i][j]=-1;//初始化名額數組

printf("遞推方法:1\n記憶化搜尋方法:2\n");

int select;

scanf("%d",&select);

if(select==1)

fnRecursive(i,j);//調用遞推方法

printf("\n%d\n",d[1][1]);

}

if(select==2)

printf("\n%d\n",fnMemorySearch(1,1));//調用記憶化搜尋方法

else

printf("輸入錯誤!");

return 0;

void fnRecursive(int i,int j)

//遞推方法實作過程

for(j=1; j<=n; j++)

d[n][j]=a[n][j];

for(i=n-1; i>=1; i--)

d[i][j]=a[i][j]+(d[i+1][j]>d[i+1][j+1]?d[i+1][j]:d[i+1][j+1]);

int fnMemorySearch(int i,int j)

//記憶化搜尋實作過程

if(d[i][j]>=0) return d[i][j];

if(i==n) return(d[i][j]=a[i][j]);

if(fnMemorySearch(i+1,j)>fnMemorySearch(i+1,j+1))

return(d[i][j]=(a[i][j]+fnMemorySearch(i+1,j)));

return(d[i][j]=(a[i][j]+fnMemorySearch(i+1,j+1)));

2、硬币問題

問題描述:有n種硬币,面值分别為V1,V2,…,Vn, 每種有無限多。給定非負整數S,可以選用多少硬币,使得面值之和恰好為S,輸出硬币數目的最小值和最大值。(1<=n<=100,0<=S<=10000,1<=Vi<=S)

// 例題1 硬币問題 //

#define INF 100000000

#define MAXNUM 10000

#define MONEYKIND 100

int n,S;

int V[MONEYKIND];

int min[MAXNUM],max[MAXNUM];

void dp(int*,int*);

void print_ans(int*,int);

//輸出函數聲明

int i;

printf("輸入硬币的種數n(1-100):\n");

printf("輸入要組合的錢數S(0-10000):\n");

scanf("%d",&S);

printf("輸入硬币種類:\n");

scanf("%d",&V[i]);

dp(min,max);

printf("最小組合方案:\n");

print_ans(min,S);

printf("\n");

printf("最大組合方案:\n");

print_ans(max,S);

void dp(int *min,int *max)

//遞推過程實作

min[0] = max[0] = 0;

for(i=1; i<=S; i++)//初始化數組

min[i]=INF;

max[i]=-INF;

for(i=1; i<=S; i++)

if(i>=V[j])

if(min[i-V[j]]+1<min[i]){

min[i]=min[i-V[j]]+1;//最小組合過程

//printf("%d\n",min[i]);

if(max[i-V[j]]+1>max[i])

max[i]=max[i-V[j]]+1;//最大組合過程

void print_ans(int *d,int S)

//輸出函數實作

if(S>=V[i]&&d[S]==d[S-V[i]]+1)

printf("%d-",V[i]);

print_ans(d,S-V[i]);

break;

3、矩形嵌套問題

問題描述:有n個矩形,每個矩形可以用兩個整數a,b描述,表示它的長和寬。矩形X(a,b)可以嵌套在矩形Y(c,d)中,當且僅當a<c,b<d或者b<c,a<d(相當于把矩形X旋轉90度)。例如(1,5)可以嵌套在(6,2)内,但不能嵌套在(3,4)内。你的任務是選出盡量多的矩形排成一行,使得除了最後一個之外,每一個矩形都可以嵌套在下一個矩形内。

// 例題2 矩形嵌套問題 //

#define MAXNUM 100//矩形的最大個數

struct Rect

int x;

int y;

};

int n;//矩形個數

struct Rect rect[MAXNUM];

int G[MAXNUM][MAXNUM];//鄰接有向圖

int d[MAXNUM];//過程數組

int dp(int i,int G[MAXNUM][MAXNUM]);

int i,j,z;

printf("輸入矩形個數n(1-100):\n");

printf("輸入矩形的長和寬:\n");

scanf("%d",&rect[i].x);

scanf("%d",&rect[i].y);

if(rect[i].x<rect[j].x&&rect[i].y<rect[j].y)

G[i][j]=1;

printf("輸入要開始的矩形z:\n");

scanf("%d",&z);

//printf("%d-",z);

int temp = dp(z,G);

printf("最大可嵌套個數:%d\n",temp);

int dp(int i,int G[MAXNUM][MAXNUM])

int j;

if(d[i]>0)

return d[i];

d[i]=1;

if(G[i][j])

if(dp(j,G)+1>d[i])

d[i]=dp(j,G)+1;

4、求一組數列的最長的不下降序列。

問題描述:設有一個正整數序列b1,b2,b3,……,bn,若下标為i1<i2<i3,……<ik且有bi1≤bi2≤……bik則稱存在一個長度為k的不下降序列。可能有多個不下降序列,輸出最長序列的長度。

樣例輸入:13 7 9 16 38 24 37 18

 樣例輸出:5 (7 9 16 24 37)

// 例題2 數組的最長不下降序列問題 //

#define MAXNUM 100//最大數字個數

int b[MAXNUM][2];

int n;

int len;

printf("輸入數列中數字的個數n(1-100):\n");

printf("輸入數字:\n");

scanf("%d",&b[i][0]);

b[i][1]=1;

for(i=2; i<=n; i++)

len = 0;

for(j=1; j<i; j++)

if((b[i][0]>=b[j][0])&&(b[j][1]>len))

len=b[j][1];

if(len>0)

b[i][1]=len+1;

len = 1;

for(j=2; j<=n; j++)

if(b[j][1]>len)

len = b[j][1];

printf("最長為:%d\n",len);

5、0-1背包問題

給定n種物品和一背包。物品i的重量是wi,其價值為vi,背包的容量為C。問應如何選擇裝入背包的物品,使得裝入背包中物品的總價值最大?

// 0-1背包問題 //

#define MAXN 100//物品種類最大數量

int w[MAXN],V[MAXN];

int C;//最大容量

int n;//物品種類

int d[MAXN][MAXN];

int jMax;

int min(int,int);

//兩數之間的最小值

int max(int,int);

//兩數之間的最大值

void print_ans(int d[][MAXN],int,int);

//構造最優解并輸出

printf("輸入物品種類數n(1-100):\n");

printf("輸入每個種類的重量:\n");

scanf("%d",&w[i]);

printf("輸入每個種類的價值:\n");

printf("輸入背包的容量C:\n");

scanf("%d",&C);

jMax=min(C,w[n]-1);

for(j=0; j<=jMax; j++)