动态规划 经典例题|数塔、货郎担问题、找零钱

数塔问题

观察下面的数字金字塔。写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。在这里插入图片描述
在上面的样例中,从7→3→8→7→5 的路径最大

状态转移方程: f[i][j] = max(f[i + 1][j],f[i + 1][j + 1]) + a[i][j];【i从n->1进行更新】

                                i>n时,f[i][j]=0;i=n 时 f[i][j]=a[i][j];

想象成填表,从最后一行开始,自底向上,每一行自左向右;

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;
int a[N][N];//存储数塔
int f[N][N];//表示从第i行第j列到第n行的最大路径
int n;

int main()
{
    while (cin >> n)
    {
        for (int i = 1;i <= n;i++)
            for (int j = 1;j <= i;j++)
                cin >> a[i][j];
                
        for (int i = n;i >= 1;i--)//用i来表示行,且从最后一行开始
            for (int j = 1;j <= i;j++)//每行有i列,且从第一列开始
                f[i][j] = max(f[i + 1][j],f[i + 1][j + 1]) + a[i][j];//自底向上计算最长路径
                
        cout << f[1][1] << endl;//当for循环结束完毕之后f[1][1]:从数塔第1行第1列开始的最长路径
    }
    return 0;
}

TSP旅行商问题

一个售货员必须访问n个城市,恰好访问每个城市一次,并最终回到出发城市。
售货员从城市i到城市j的旅行费用是一个整数,旅行所需的全部费用是他旅行经过的的各边费用之和,而售货员希望使整个旅行费用最低。

状态转移方程

 依旧是填表, 用索引的二进制的每一位表示是否走过城市


void Tsp_getShoretstDistance()
{               
	int i,j,k;
	//初始化第一列
	for(i=0;i<city_number;i++)
	{
		process[i][0]=distance[i][0];//V为空集的情况
	}
	//初始化剩余列
	for(j=1;j<(1<<(city_number-1));j++)//对每一个 i, V集合有 1<<(city_number-1)种可能
	{
		for(i=0;i<city_number;i++)
		{
			process[i][j]=0x7ffff;//process是从i开始,经过由“j”确定的集合,回到0点走的距离
 
			//对于数字x,通过判断布尔表达式 (((x >> (i - 1) ) & 1) == 1的真值来实现要看它的第i位是不是1,第i位为1表示第i个城市在V集合中
 
			if(((j>>(i-1))&1)==1)
			{
				continue;//第i个城市在V集合中
			}
			for(k=1;k<city_number;k++)//遍历集合V的元素,寻找从i经过V的最短距离
			{
				 
				if(((j>>(k-1))&1)==0)
				{
					continue;//第k个城市不在V集合中
				}
				if(process[i][j]>distance[i][k]+process[k][j ^ (1 << (k - 1))])
				{
					process[i][j]=distance[i][k]+process[k][j ^ (1 << (k - 1))];				
					//i走向V中的K点,K走向V中剩余元素
				}
			}
		}
	}
	cout<<"最短路径长度:";
	cout<<"sum="<<process[0][(1<<(city_number-1))-1]<<endl;
}
 

零钱兑换


给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 0 。你可以认为每种硬币的数量是无限的。

算法设计思路:
设F(n)是总金额为n的最少硬币数
                n>0时,F(n)=min{F(n-dj)}+1 (n>=dj)
                n=0时,F(0)=0;

int changeMaking(int D[],int m,int n) //m为D的len,n为金额
    {   int i;
        F[0]=0;
        for(i=1;i<=n;i++) //从1 到n的各个值所需的币数
            {
                int temp=10000,j=1;
                while(j<=m and i>=D[j])
                {   temp=min(F[i-D[j]],temp);
                    j=j+1;
                }
                F[i]=temp+1;

            }
        return F[n];

    }

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值