最头疼的就是这一块 老师上课又飞快,虽然讲的非常好,但是还是有点跟不上节奏,加之老师根本不分析代码,所以自己考前准备自己动手复习一波。
动态规划解决问题的基本方法码一波
(1)找出最优解的性质并刻画其结构特征
(2)递归地定义最优值
(3)以自底向上的方式计算出最优值
(4)根据计算最优值时的信息构造最优解
矩阵连乘的最优值是n个矩阵连乘的最小数乘次数,最优解是得出矩阵之间该如何进行优先级运算才能得出最优值(也就是加括号的方式)
题目描述
给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,i=1,2 ,…,n-1。如何确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。
A1={30x35} ; A2={35x15} ;A3={15x5} ;A4={5x10} ;A5={10x20} ;A6={20x25} ;
最后的结果为:((A1(A2A3))((A4A5)A6)) 最小的乘次为15125
Code
#include
using namespace std;
int m[100][100]; //m[i][j]表示A[i:j]的最小数乘次数
int s[100][100]={0}; //s[i][j]表示断点位置
int p[100]; //表示矩阵的行列值
int matrixchain(int n)
{
for(int i=0;i<=n;i++)
{
m[i][i]=0; //对角线赋值0
}
for(int r=2;r<=n;r++)
{
for(int i=1;i<=n-r+1;i++)
{
int j=i+r-1; //从m[i][i+1]开始判断 i<=j<n
m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];
s[i][j]=i; //此时从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]; //从i+1处断开并比较大小
if(t<m[i][j])
{
m[i][j]=t; //更新最优值
s[i][j]=k; //更新断点
}
}
}
}
}
int main()
{
int N;
cin>>N;
for(int i=0;i<N+1;i++)
{
cin>>p[i];
}
matrixchain(N);
cout<<m[1][N]<<endl;
system("pause");
return 0;
}
题目描述
给你一个序列X和另一个序列Z,当Z中的所有元素都在X中存在,并且在X中的下标顺序是严格递增的,那么就把Z叫做X的子序列。
例如:Z=是序列X=的一个子序列,Z中的元素在X中的下标序列为<1,2,4,6>。
现给你两个序列X和Y,请问它们的最长公共子序列的长度是多少?
code
#include
using namespace std;
int c[100][100];
int b[100][100];
char x[100],y[100];
int lcslength(int m,int n) //构造最优值,以及最优解需要的条件b[i][j]
{
int i,j;
for(i=1;i<=m;i++)c[i][0]=0;
for(i=1;i<=n;i++)c[0][i]=0;
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
{
if(x[i]==y[j])
{
c[i][j]=c[i-1][j-1]+1;
b[i][j]=1;
}
else
{
if(c[i-1][j]>=c[i][j-1])
{
c[i][j]=c[i-1][j];
b[i][j]=2;
}
else
{
c[i][j]=c[i][j-1];
b[i][j]=3;
}
}
}
}
}
void lcs(int i,int j) //构造最优解
{
if(i==0||j==0)
{
return;
}
if(b[i][j]==1)
{
lcs(i-1,j-1);
cout<<x[i]<<" ";
}
else if(b[i][j]==2)
{
lcs(i-1,j);
}
else
{
lcs(i,j-1);
}
}
int main()
{
int m,n;
cin>>m>>n;
for(int i=1;i<=m;i++)
{
cin>>x[i];
}
for(int i=1;i<=n;i++)
{
cin>>y[i];
}
lcslength(m,n);
cout<<"length="<<c[m][n]<<endl;
lcs(m,n);
return 0;
}
题目描述
给定n个整数组成的序列a1,a2,…an, 求子段和ai+ai+1+…+aj(子段可为空集)的最大值。
提示:子段可为空集,答案为0
输入
包含多组测试数据。第一行为一个整数T(1<=T<=20),代表测试数据个数。
每组测试数据第一行为一个整数n,代表有n个整数(1<=n<=10000)。
接下来一行有n个数x(-1000<=x<=1000)。
1
6
2 -11 4 13 -1 2
输出
输出其对应的最大子段和。
18
code
#include
using namespace std;
int a[100];
int sum=0;
int maxsum(int n)
{
int b=0;
for(int i=0;i<n;i++)
{
if(b>0)
{
b+=a[i];
}
else
{
b=a[i];
}
if(b>sum)
{
sum=b;
}
}
}
int main()
{
int k;
cin>>k;
for(int i=0;i<k;i++)
{
cin>>a[i];
}
maxsum(k);
cout<<sum<<endl;
return 0;
}
题目描述
已知有N种物品和一个可容纳C重量的背包。每种物品i的重量为Wi,价值为Pi。那么,采用怎样的装包方法才会使装入背包物品的总价值最大。
输入
包含多组测试数据。第一行为一个整数T(1<=T<=10),代表测试数据个数。
接下来有T组测试数据。每组测试数据第一行为背包的重量C(C<10000)和物品个数N(N<1000)。接下来的N行分别为物品的重量cost和价值
(注意:结果可能超过int范围)
1
10 5
2 6
2 3
6 5
5 4
4 6
输出
对每组测试数据,输出其对应的所装物品的最大价值。
15
code
#include
using namespace std;
int m[100][100]={0};
int w[100];
int v[100];
int knapsack(int n,int c)
{
int jmax=min(w[n]-1,c);
for(int i=0;i<=jmax;i++)
{
m[n][i]=0;
}
for(int i=w[n];i<=c;i++)
{
m[n][i]=v[n];
}
for(int i=n-1;i>=1;i--)
{
jmax=min(w[i]-1,c);
for(int j=0;j<=jmax;j++)
{
m[i][j]=m[i+1][j];
}
for(int j=w[i];j<=c;j++)
{
m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]);
}
}
}
int main()
{
int t;
cin>>t;
while(t--)
{
int c,n;
cin>>c>>n;
for(int i=1;i<=n;i++)
{
cin>>w[i]>>v[i];
}
knapsack(n,c);
cout<<m[1][c]<<endl;
}
return 0;
}
例题
题目描述
Bessie像她的诸多姊妹一样,因為从FarmerJohn的草地吃了太多美味的草而长出了太多的赘肉。所以FJ将她置於一个及其严格的节食计划之中。她每天不能吃多过H(5<=H<=45000)公斤的乾草。Bessie只能吃一整綑乾草;当她开始吃一綑乾草的之后就再也停不下来了。她有一个完整的N(1<=n<=50)綑可以给她当作晚餐的乾草的清单。她自然想要尽量吃到更多的乾草。很自然地,每綑乾草只能被吃一次(即使在列表中相同的重量可能出现2次,但是这表示的是两綑乾草,其中每綑乾草最多只能被吃掉一次)。给定一个列表表示每綑乾草的重量Si(1<=Si<=H),求Bessie不超过节食的限制的前提下可以吃掉多少乾草(注意一旦她开始吃一綑乾草就会把那一綑乾草全部吃完)。
输入
第一行:两个由空格隔开的整数:H和N, 第2到N+1行:第i+1行是一个单独的整数,表示第i綑乾草的重量Si。
56 4
15
19
20
21
输出
一个单独的整数表示Bessie在限制范围内最多可以吃多少公斤的乾草。
56
code
#include
#include
#include
#define inf 0x7fffffff
using namespace std;
int main()
{
int c; //最多吃的干草量
int n; //有多少捆干草
cin >> c >> n;
int *wei = new int[n + 1];
int m[50000];
for (int i = 1; i <= n; i++)
{
cin >> wei[i];
}
memset(m, 0, sizeof(m));
for (int i = 1; i <= n; i++)
{
for (int j = c; j >= wei[i]; j--) //j从大到小倒着遍历,如果大于重量,则说明可以放入,反之,则放弃这个物品,从下一个物品开始
{
m[j] = max(m[j], m[j - wei[i]] + wei[i]);
}
}
cout << m[c] << endl;
}
题目描述
给定n个矩阵{A1,A2,...,An},及m个矩阵连乘的表达式,判断每个矩阵连乘表达式是否满足矩阵乘法法则,如果满足,则计算矩阵的最小连乘次数,如果不满足输出“MengMengDa“。
输入
输入数据由多组数据组成(不超过10组样例)。每组数据格式如下:
第一行是2个整数n (1≤n≤26)和m(1≤m≤3),表示矩阵的个数。
接下来n行,每行有一个大写字母,表示矩阵的名字,后面有两个整数r和c,分别表示该矩阵的行数和列数,其中1
code
#include
#include
using namespace std;
int m[100][100]={0};
int p[200];
int maxchain(int n)
{
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];
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;
}
}
}
}
return m[1][n];
}
int main()
{
int n,m;
while(cin>>n>>m)
{
char chain[30];
int h[30];
int l[30];
for(int i=0;i<n;i++)
{
cin>>chain[i]>>h[i]>>l[i];
}
char test[3][105];
for(int i=0;i<m;i++)
{
cin>>test[i];
}
int key;
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if(test[i][0]==chain[j])
{
key=j;
break;
}
}
p[0]=h[key];
p[1]=l[key];
int len=strlen(test[i]);
int flag=1;
for(int k=1;k<len;k++)
{
for(int j=0;j<n;j++)
{
if(test[i][k]==chain[j])
{
key=j;
break;
}
}
if(p[k]==h[key])
{
p[k+1]=l[key];
}
else
{
cout<<"MengMengDa"<<endl;
flag=0;
break;
}
}
if(flag==1)
{
cout<<maxchain(len)<<endl;
}
}
}
}