旅行商问题解法(2024年字节跳动校招笔试算法题“毕业旅行问题”)_小明目前在做一份毕业旅行的规划。打算从北京出发,分别去若干个城市,然后再回到北

dp[1]{2,3} 只需要求出

d

p

[

2

]

{

3

}

dp[2]{3}

dp[2]{3} 即可,而

d

p

[

2

]

{

3

}

=

d

p

[

3

]

{

}

D

3

2

dp[2]{3}=dp[3]{}+D_3^2

dp[2]{3}=dp[3]{}+D32​,

d

p

[

3

]

{

}

dp[3]{}

dp[3]{} 代表从城市3回到起点的距离,也就是

d

p

[

3

]

{

}

=

D

0

3

dp[3]{}=D_0^3

dp[3]{}=D03​。

那么如何建立一个数组来表达上述状态转移方程呢?
我们可以使用状态压缩的方法,用一个int数字的每一位来表达

d

p

[

n

]

{

p

1

,

p

2

,

.

.

.

,

p

m

}

dp[n]{p_1,p_2,…,p_m}

dp[n]{p1​,p2​,…,pm​} 中的

{

p

1

,

p

2

,

.

.

.

,

p

m

}

{p_1,p_2,…,p_m}

{p1​,p2​,…,pm​},即

p

m

p_m

pm​是否存在等价于该int数字的第m位是否为1,所以一个int数字可以表达

{

p

1

,

p

2

,

.

.

.

,

p

32

}

{p_1,p_2,…,p_{32}}

{p1​,p2​,…,p32​},即32个城市。在刚才的字节跳动笔试题中,题目已经给出

n

20

n\leq20

n≤20,所以使用一个int数字已经足够了。所以最后,dp数组的宽度为城市的数量

x

x

x,长度为

2

x

1

2^{x-1}

2x−1。

所以该算法的时间复杂度为

O

(

2

n

n

2

)

O(2nn2)

O(2nn2),空间复杂度为

O

(

2

n

)

O(2^n)

O(2n),虽然看上去时间复杂度还是很大,但好在基数

n

n

n 并不大,所以一般在

n

<

20

n<20

n<20几秒钟就能解决问题。要知道在

n

=

20

n=20

n=20的时候,和回溯法相比理论效率提高了50亿倍,时间开销小了很多。

解决数组问题后,接下来就是建立初始状态。
刚才已经说过

d

p

[

n

]

{

}

=

D

0

n

dp[n]{}=D_0^n

dp[n]{}=D0n​,所以我们可以把各个城市n到起点的距离

D

0

n

D_0^n

D0n​赋值给

d

p

[

n

]

[

0

]

dp[n][0]

dp[n][0]:

int[][] dp = new int[n][1 << (n - 1)];
for(int i = 0; i < n; i++) {
	dp[i][0] = map[i][0];
}

接下来就是考虑如何填充dp表。
首先,我们现在已知

d

p

[

1

]

{

}

,

d

p

[

2

]

{

}

,

.

.

.

,

d

p

[

n

]

{

}

dp[1]{},dp[2]{},…,dp[n]{}

dp[1]{},dp[2]{},…,dp[n]{}的值
例如选定

d

p

[

1

]

{

}

dp[1]{}

dp[1]{},我们可以直接推导出

d

p

[

0

]

{

1

}

,

d

p

[

2

]

{

1

}

,

.

.

.

,

d

p

[

m

]

{

1

}

dp[0]{1},dp[2]{1},…,dp[m]{1}

dp[0]{1},dp[2]{1},…,dp[m]{1}(因为

d

p

[

n

]

{

1

}

=

d

p

[

1

]

{

}

D

1

m

dp[n]{1}=dp[1]{}+D_1^m

dp[n]{1}=dp[1]{}+D1m​)
同理选定

d

p

[

n

]

{

}

dp[n]{}

dp[n]{},我们可以直接推导出

d

p

[

0

]

{

n

}

,

d

p

[

2

]

{

n

}

,

.

.

.

,

d

p

[

m

]

{

n

}

dp[0]{n},dp[2]{n},…,dp[m]{n}

dp[0]{n},dp[2]{n},…,dp[m]{n}(因为

d

p

[

m

]

{

n

}

=

d

p

[

m

]

{

}

D

n

m

dp[m]{n}=dp[m]{}+D_n^m

dp[m]{n}=dp[m]{}+Dnm​)

所以第一个循环为遍历城市集合,即依次遍历

{

1

}

,

{

2

}

,

{

1

,

2

}

,

{

3

}

,

{

1

,

3

}

,

{

2

,

3

}

,

{

1

,

2

,

3

}

,

.

.

.

,

{

1

,

.

.

.

,

n

}

{1},{2},{1,2},{3},{1,3},{2,3},{1,2,3},…,{1,…,n}

{1},{2},{1,2},{3},{1,3},{2,3},{1,2,3},…,{1,…,n},因为只有根据小的集合才能推导出大的集合,将这个集合

P

P

P 对应的int数赋值为

X

X

X(下列代码中为p):

for (int p = 1; p < 1 << (n - 1); p++) {
	//...
}

第二个循环选择起点城市(当然起点城市不能包含在

P

P

P 中 ),并将起始城市赋值给变量

i

i

i,此时城市集合和起点城市就选定好了,也就是我们要计算的

d

p

[

i

]

[

p

]

dp[i][p]

dp[i][p]:

for (int p = 1; p < 1 << (n - 1); p++) {  //遍历所有集合
	for (int i = 0; i < n; i++) {  //选定一个起点城市
		if(self(i, p)) {  //起点城市不能包含在P中 
        	continue;
        }
        //...
    }
}

如何计算

d

p

[

i

]

[

p

]

dp[i][p]

dp[i][p]呢,我们之前之前提过:

d

p

[

n

]

{

p

1

,

p

2

,

.

.

.

,

p

m

}

=

m

i

n

(

d

p

[

p

1

]

{

p

2

,

.

.

.

,

p

m

}

D

p

1

n

,

d

p

[

p

2

]

{

p

1

,

p

3

,

.

.

.

,

p

m

}

D

p

2

n

,

.

.

.

.

.

.

,

d

p

[

p

m

]

{

p

1

,

p

2

,

.

.

.

p

m

1

}

D

p

m

n

)

dp[n]{p_1,p_2,…,p_m}= min(dp[p_1]{p_2,…,p_m}+D_{p_1}^n, dp[p_2]{p_1,p_3,…,p_m}+D_{p_2}n,…,dp[p_m]{p_1,p_2,…p_{m-1}}+D_{p_m}n)

dp[n]{p1​,p2​,…,pm​}=min(dp[p1​]{p2​,…,pm​}+Dp1​n​,dp[p2​]{p1​,p3​,…,pm​}+Dp2​n​,…,dp[pm​]{p1​,p2​,…pm−1​}+Dpm​n​)

所以第三个循环就是从集合

P

P

P 中选取每个城市作为子问题的起点

p

x

p_x

px​,也就是需要计算

d

p

[

p

x

]

旅行商问题解法(2024年字节跳动校招笔试算法题“毕业旅行问题”)_小明目前在做一份毕业旅行的规划。打算从北京出发,分别去若干个城市,然后再回到北_第1张图片
旅行商问题解法(2024年字节跳动校招笔试算法题“毕业旅行问题”)_小明目前在做一份毕业旅行的规划。打算从北京出发,分别去若干个城市,然后再回到北_第2张图片
旅行商问题解法(2024年字节跳动校招笔试算法题“毕业旅行问题”)_小明目前在做一份毕业旅行的规划。打算从北京出发,分别去若干个城市,然后再回到北_第3张图片

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

加入社区》https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0

=

m

i

n

(

d

p

[

p

1

]

{

p

2

,

.

.

.

,

p

m

}

D

p

1

n

,

d

p

[

p

2

]

{

p

1

,

p

3

,

.

.

.

,

p

m

}

D

p

2

n

,

.

.

.

.

.

.

,

d

p

[

p

m

]

{

p

1

,

p

2

,

.

.

.

p

m

1

}

D

p

m

n

)

dp[n]{p_1,p_2,…,p_m}= min(dp[p_1]{p_2,…,p_m}+D_{p_1}^n, dp[p_2]{p_1,p_3,…,p_m}+D_{p_2}n,…,dp[p_m]{p_1,p_2,…p_{m-1}}+D_{p_m}n)

dp[n]{p1​,p2​,…,pm​}=min(dp[p1​]{p2​,…,pm​}+Dp1​n​,dp[p2​]{p1​,p3​,…,pm​}+Dp2​n​,…,dp[pm​]{p1​,p2​,…pm−1​}+Dpm​n​)

所以第三个循环就是从集合

P

P

P 中选取每个城市作为子问题的起点

p

x

p_x

px​,也就是需要计算

d

p

[

p

x

]

[外链图片转存中…(img-RPC3aLqR-1725788429195)]
[外链图片转存中…(img-UM64m55E-1725788429195)]
[外链图片转存中…(img-rcaPIzQl-1725788429196)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

加入社区》https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0

你可能感兴趣的:(算法,动态规划)