题目

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