【蓝桥杯】第十二届蓝桥杯B组C/C++省赛,试题E:路径

题目

在这里插入图片描述

思路

  • 这个题不能用DFS或者BFS求解,因为分支太多,由题意,差值小于等于21的才能相连,所以每一步往后走有21种选择方案。
  • 显而易见,本题需要用DP(动态规划)来求解。
  1. 那么我们用动态规划的思想来思考这个路径问题,题目:结点1和结点2021之间的最短路径长度不能直接求得,而结点2021仅与[2000,2001,2002…2020]有边相连,不难得出,1~2021最短路径=min[ (1-2000最短路径+2000-2021边长度) ,(1-2001最短路径+2001-2021边长度),(1-2002最短路径+2000-2021边长度)…,(1-2020最短路径+2020-2021边长度)],也就是我们所看到的21种到结点2021方案中最小值方案。
  2. 但是上面21种方案中,1-2000最短路径、1-2001最短路径、1-2002最短路径…1-2020最短路径 我们不知道。到这一步应该先到dp的思路,同样地,1-2000最短路径=min(1-1979最短路径+1979-2000边长度…1-1999最短路径+1999-2000边长度),依次类推。
  3. 这样思路是有了,但是这样从2021结点往前推 还是不太好编程实现。所以我们从前往后推,依次将数据补充。从结点1最远只和结点22有边相连,那么1~2的最短路径就是2(1,2的最小公倍数),1-3的最短路径是3…1-22的最短路径是22,1-23的最短路径不知道,但是根据公式可以求得
    1-23最短路径=min[ (1-2最短路径+2-23边长度) ,(1-3最短路径+3-23边长度),(1-4最短路径+4-23边长度)…,(1-22最短路径+22-23边长度)],取得21种 从1~23 方案中路径最小的方案,这就是动态规划的思路。
  4. 1-23的最短路径可以求出,因为1-2,1-3…1-22的最短路径都知道,根据动态规划,这样正向推导,有了1-23最短路径,可以求得1-24最短路径,从而求得1-25,1-26…1-2021最短路径
  5. 如何编程实现dp,用一个数组 a[],a[ i ]表示从结点1~结点 i 的最短路径,这样目标是得到a[ 2021]的值,由之前的分析,a[2]=2,a[3]=3 …a[22]=22a[23]=min(a[2]+length(2,23) , a[3]+length(3,23)… a[22]+length(22,23) )。这样依次求出a[24] , a[25] … a[2021]。
  6. 补充,两结点有边相连,长度为最小公倍数,最小公倍数直接套模板,模板在代码中呈现。

代码

#include<iostream>
using namespace std;
typedef long long LL;
const int N = 2022;
LL a[N];

//公约
int gcd(int a,int b)
{
	return b==0?a:gcd(b,a%b);
 } 
//公倍
int lcm(int a,int b)
{
	return a*b/gcd(a,b);
 }
int main()
{
	int i=1;
	//初始化数组 1-22 
	for(;i<=22;i++)
	{
		a[i]=i;
	}
	//填充数组 23-2021的值 
	for(;i<=2021;i++)
	{
		LL minn;
		int j=21;
		a[i]=a[i-j]+lcm(i-j,i);
		//在 21 种方案中选择最小的方案 
		while(j>0){
			if( a[i-j]+lcm(i-j,i)<a[i])
				a[i]=a[i-j]+lcm(i-j,i);
			j--;
		}
	}
	cout<<a[2021];
	return 0;
}
  • 34
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值