湖州师范学院实验报告
课程名称:算法
实验二:动态规划方法及其应用
一、实验目的
1、掌握动态规划方法的基本思想和算法设计的基本步骤。
2、应用动态规划方法解决实际问题。
二、实验内容
1、问题描述
1 )背包问题
给定 N 种物品和一个背包。
物品 i 的重量是 C i ,价值为 W i ;背包的容量为 V。
问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大?在选择装入背包的物品,对每种物品只有两个选择:装入或不装入,且不能重复装入。
输入数据的第一行分别为:背包的容量 V,物品的个数 N。
接下来的 N 行表示 N 个物品的重量和价值。
输出为最大的总价值。
2)矩阵连乘问题
给定 n 个矩阵:A1,A2,...,An,其中 Ai 与 Ai+1 是可乘的,i=1 , 2... , n-1。
确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。
输入数据为矩阵个数和每个矩阵规模,输出结果为计算矩阵连乘积的计算次序和最少数乘次数。
3 )LCS问题
给定两个序列,求最长的公共子序列及其长度。
输出为最长公共子序列及其长度。
2、数据输入:文件输入或键盘输入。
3、要求:
1)完成上述两个问题,时间为 2 次课。
2)独立完成实验及实验报告。
三、实验步骤
1、理解方法思想和问题要求。
2、采用编程语言实现题目要求。
3、上机输入和调试自己所写的程序。
4、附程序主要代码:
(1) #include<stdio.h>
int max(int a, int b)
{
return (a > b)? a : b;
}
int knapSack(int W, int wt[], int val[], int n)
{
if (n == 0 || W == 0)
return 0;
if (wt[n-1] > W)
return knapSack(W, wt, val, n-1);
else return max( val[n-1] + knapSack(W-wt[n-1], wt, val, n-1),
knapSack(W, wt, val, n-1)
);
}
int main()
{
int val[] = {60, 100, 120};
int wt[] = {10, 20, 30};
int W = 50;
int n = sizeof(val)/sizeof(val[0]);
printf("%d", knapSack(W, wt, val, n));
return 0;
}
(2) #include <stdio.h>
#include <iostream>
using namespace std;
const int L = 7;
int MatrixChain(int n,int **m,int **s,int *p);
void Traceback(int i,int j,int **s);
int main()
{
int p[L]={30,35,15,5,10,20,25};
int **s = new int *[L];
int **m = new int *[L];
for(int i=0;i<L;i++)
{
s[i] = new int[L];
m[i] = new int[L];
}
cout<<"矩阵的最少计算次数为:"<<MatrixChain(6,m,s,p)<<endl;
cout<<"矩阵最优计算次序为:"<<endl;
Traceback(1,6,s);
return 0;
}
int MatrixChain(int n,int **m,int **s,int *p)
{
for(int i=1; i<=n; i++)
{
m[i][i] = 0;
}
for(int r=2; r<=n; r++)
{
for(int i=1; i<=n-r+1; i++)
{
int j = i+r-1;
m[i][j] = m[i+1][j] + p[i-1]*p[i]*p[j];
s[i][j] = i;
for(int k=i+1; k<j; k++)
{
int t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j]; if(t<m[i][j])
{
m[i][j] = t;
s[i][j] = k;
}
}
}
}
return m[1][L-1];
}
void Traceback(int i,int j,int **s)
{
if(i==j) return;
Traceback(i,s[i][j],s);
Traceback(s[i][j]+1,j,s);
cout<<"Multiply A"<<i<<","<<s[i][j];
cout<<" and A"<<(s[i][j]+1)<<","<<j<<endl;
}
(3)#include<bits/stdc++.h>
int max(int a, int b);
int lcs( char *X, char *Y, int m, int n )
{
if (m == 0 || n == 0)
return 0;
if (X[m-1] == Y[n-1])
return 1 + lcs(X, Y, m-1, n-1);
else
return max(lcs(X, Y, m, n-1), lcs(X, Y, m-1, n));
}
int max(int a, int b)
{
return (a > b)? a : b;
}
int main()
{
char X[] = "AGGTAB";
char Y[] = "GXTXAYB";
int m = strlen(X);
int n = strlen(Y);
printf("Length of LCS is %d\n", lcs( X, Y, m, n ) );
return 0;
}
5、实验结果:
(1)
(2)
(3)
四、实验分析
1、01背包问题分析:
第一,包的容量比该商品体积小,装不下,此时的价值与前i-1个的价值是一样的,即
V(i,j)=V(i-1,j);
第二,还有足够的容量可以装该商品,但装了也不一定达到当前最优价值,所以在
装与不装之间选择最优的一个,即Val(i,j)=max{Val(i-1,j),Val(i-1,j-wal(i))+val(i) }其中V(i-1,j)表示不装,Val(i-1,j-wt(i))+val(i) 表示装了第i个商品,背包容
量减少wt(i)但价值增加了val(i);
由此可以得出递推关系式:
1) j<wt(i) Val(i,j)=Val(i-1,j)
2) j>=wt(i) Val(i,j)=max{ Val(i-1,j),Val(i-1,j-wt(i))+val(i) }
核心代码:int knapSack(int W, int wt[], int val[], int n)
{
if (n == 0 || W == 0)
return 0;
if (wt[n-1] > W)
return knapSack(W, wt, val, n-1);
else return max( val[n-1] + knapSack(W-wt[n-1], wt, val, n-1),
knapSack(W, wt, val, n-1)
);
}
2、矩阵连乘问题分析:
计算矩阵连乘乘积A1A2A3A4A5A6,其中各矩阵的维数分别是:
A1:30*35; A2:35*15; A3:15*5; A4:5*10; A5:10*20; A6:20*25
设计算A[i:j],1≤i≤j≤n,所需要的最少数乘次数m[i,j],则原问题的最优值为m[1,n]。
当i=j时,A[i:j]=Ai,因此,m[i][i]=0,i=1,2,…,n
当i<j时,若A[i:j]的最优次序在Ak和Ak+1之间断开,i<=k<j,则:m[i][j]=m[i][k]+m[k+1][j]+pi-1pkpj。
由于在计算是并不知道断开点k的位置,所以k还未定。
不过k的位置只有j-i个可能。
因此,k是这j-i个位置使计算量达到最小的那个位置。
3、LCS问题分析:。