矩阵连乘问题
算法思路: 求A[1] 到 A[n] 相乘的最小次数,这个问题是有最优子结构的,可以用区间dp来解决, 我们可以通过加括号来决定矩阵连乘的顺序,对于i到j的矩阵相乘,因为每次都是将区间分为俩个部分,所以枚举中间节点 k ,然后找到一个最小的值,同时记录一个分割点k还有这个最小值, st[i][j] = k,f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j] + a[i] * a[j + 1] * a[k +1] ,下面我们用一个集合表示法来表示一下这个问题
最后dfs找到一条路径即可
算法描述:
区间dp,就是先求小区间的最优解,然后逐步合并到大区间的最优解,找状态转移方程。f[i][j]一般是表示i~j区间的数字相加的最小代价。每次用变量k将其分成(i~k和k+1~j)两段
code:
#include<iostream>
#include<algorithm>
#include<cstring>
#define INF 0x3f3f3f3f
using namespace std;
const int N = 1100;
int f[N][N];//f[i][j]表示从i到j最小计算量
int st[N][N];// 记录拆开的位置
int a[N];
void dfs(int l, int r){
if(l == r){
printf("A[%d]", l);
return;
}
int k = st[l][r];
printf("(");
dfs(l, k),dfs(k + 1, r);
printf(")");
}
int main()
{
int n;//一共有n个矩阵
scanf("%d" ,&n);
printf("每个矩阵的行和最后一个矩阵的列分别为为\n");
memset(f, INF ,sizeof f);
for(int i = 1;i <= n ;i ++) f[i][i] = 0;//一个矩阵相乘就是一次
for(int i = 1; i <= n + 1; i ++) cin >> a[i];//第i个矩阵的列就是第i + 1的矩阵的行
for(int len = 2 ; len <= n ;len ++)//枚举区间长度
for(int i = 1; i + len - 1 <= n ; i++){//枚举区间左端点
int j = i + len -1;//右端点
//枚举中间点k
for(int k = i ;k < j; k ++){
int minx = f[i][k] + f[k + 1][j] + a[i] * a[j + 1] * a[k + 1];// 第k个矩阵的列就是k + 1
if(minx < f[i][j]){
f[i][j] = minx;
st[i][j] = k;// 更新分割点
}
}
}
printf("矩阵连乘的最小次数为 : %d\n",f[1][n]);
printf("过程为 : \n");
dfs(1, n);
return 0;
}
算法结果:
找零钱问题:
算法思路:
商品的价格为n , 你付 m, 那么商家要找m - n 元, 现在有100 50 30 10 5 1 让你求最少的需要找多少张钱。 这个题局部最优解就是整体最优解,所以用贪心算法来做, 每次贪心用最大的钱。
算法描述:
贪心法,指的是从问题的初始状态出发,通过若干次的贪心选择而得出最优值(或较优解)的一种解题方法。
其实,从“贪心策略”一词我们便可以看出,贪心策略总是做出在当前看来是最优的选择,也就是说贪心策略并不是从整体上加以考虑,它所做出的选择只是在某种意义上的局部最优解,而许多问题自身的特性决定了该题运用贪心策略可以得到最优解或较优解。
贪心算法的基本要素:1.贪心选择性质。 2,最优子结构
code:
#include<iostream>
using namespace std;
int a[110];//记录需要每种面值的纸币的个数
int main()
{
int n;
cin >> n;//输入要找的钱数
int ans = 0;//最少需要找的钱的张数
while(n){
int x;
//从大到小枚举纸币的面值
if(n >= 100){
x = n / 100;
a[100] = x;
ans += x;
n %= 100;
}
else if(n >= 50){
x = n / 50;
a[50] = x;
ans += x;
n %= 50;
}
else if(n >= 30){
x = n / 30;
a[30] = x;
ans += x;
n %= 30;
}
else if(n >= 10){
x = n / 10;
a[10] = x;
ans += x;
n %= 10;
}
else if(n >= 5){
x = n / 5;
a[5] = x;
ans += x;
n %= 5;
}
else{
a[1] = n;
ans += n;
n %= 1;
}
}
printf("最少需要找的钱的张数:%d\n",ans);
for(int i = 1 ;i <= 100 ; i++){
if(a[i] != 0){
cout << i << " : " << a[i] << endl;
}
}
return 0;
}
// 每次贪心选择最大的数值的即可
算法结果: