c语言塔树,树塔

前几天做了好几个DP题目,感觉都是一个类型的,因此有必要总结一下。

0818b9ca8b590ca3270a3433284dd417.png

数塔问题 :要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?

分析:站在位置9,我们可以选择沿12方向移动,也可以选择沿着15方向移动,现在我们假设“已经求的”沿12方向的最大值x和沿15方向的最大值y,那么站在9的最大值必然是:Max(x,y) + 9。

因此不难得出,对于任意节点i,其状态转移方程为:m[i] = Max(a[i的左孩子] , a[i的右孩子]) + a[i]

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

#include

<

stdio.h

>

#define

N 10000

#define

Max(a,b) ((a) > (b) ? (a) : (b))

int

a[N];

int

main(

void

) {

int

n , m , i , k , j; scanf(

"

%d

"

,

&

m);

while

(m

--

>

0

) { scanf(

"

%d

"

,

&

n); k

=

(

1

+

n)

*

n

/

2

;

for

(i

=

1

; i

<=

k; i

++

) { scanf(

"

%d

"

,a

+

i); } k

=

k

-

n;

for

(i

=

k , j

=

0

; i

>=

1

; i

--

) { a[i]

=

a[i]

+

Max(a[i

+

n],a[i

+

n

-

1

]);

if

(

++

j

==

n

-

1

) { n

--

; j

=

0

; } } printf(

"

%d\n

"

,a[

1

]); }

return

0

; }

0818b9ca8b590ca3270a3433284dd417.png

首先什么是“数塔类型”?从某一点转向另一点或者说是从某一状态转向另一状态,有多种选择方式(比如这里的9->12 , 9->15),从中选取一条能产生最优值的路径。

这类问题的思考方法:假设后续步骤的结果已知,比如这里假设已经知道沿12方向的最大值x和沿15方向的最大值y。

接下来看几个题,加深印象吧

1.免费馅饼问题

5 (起始位置)

4       |      5       |       6

3   4   5  |  4   5   6  |  5   6   7

..................

和“数塔”一样,它也是从某一点出发,有多个选择的问题(往前走一步,呆在原地,往后走一步)从中选择一条最优值路径(获得馅饼最多)。还是按照“数塔”的思考方式,我们可以假设“已经求得”下一个站在位置4获得的最大值x和呆在原地获得的最大值y以及站在位置6获得的最大值z,那么对于起始位置5获得最大值就是Max(x,y,z) ,因此可以得到状态转移方程为:m[t][x] = Max(m[t+1][x-1] , m[t+1][x] , m[t+1][x+1])

并且我们可以通过“列表格”的方式,自底向上求解:

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

#include

<

stdio.h

>

#include

<

string

.h

>

#define

N 100000

int

a[N][

11

];

int

Max(

int

a ,

int

b ,

int

c) {

int

n; n

=

a

>

b

?

a : b;

return

n

>

c

?

n : c; }

int

main(

void

) {

int

n , x , t , max , i;

while

(scanf(

"

%d

"

,

&

n)) {

if

(

!

n)

break

; max

=

0

; memset(a ,

0

,

sizeof

(a));

for

(i

=

0

; i

<

n ; i

++

) { scanf(

"

%d%d

"

,

&

x,

&

t); a[t][x]

+=

1

;

if

(t

>

max) max

=

t; }

//

DP

for

(t

=

max

-

1

; t

>=

0

; t

--

) { a[t][

0

]

+=

Max(

0

, a[t

+

1

][

0

] , a[t

+

1

][

1

]) ;

for

(x

=

1

; x

<

10

; x

++

) { a[t][x]

+=

Max(a[t

+

1

][x

-

1

] , a[t

+

1

][x] , a[t

+

1

][x

+

1

]) ; } a[t][

10

]

+=

Max(a[t

+

1

][

9

] , a[t

+

1

][

10

] ,

0

) ; } printf(

"

%d\n

"

,a[

0

][

5

]); }

return

0

; }

0818b9ca8b590ca3270a3433284dd417.png

2.滑雪问题

左   A    右

依然和“数塔”一样,从某一点出发,面临多个选择(往上,往左,往下,往右)从中选择一条最优值路径(滑雪距离最长)

若对A点求,很显然它的最大值就为: Max(上,右,下,左) + 1

因此对于任意位置[i,j], 其状态转移方程为:m[i][j] = Max(m[i-1][j] , m[i][j+1] , m[i+1][j] , m[i][j-1]) + 1

由于这道题很难画出它的路径图(起点和终点都不知道)因此很难用“列表格”的方式自底向上求解,因此我们采用备忘录法:

0818b9ca8b590ca3270a3433284dd417.png

代码

3.Worm问题,这题和免费馅饼几乎是一样的,我们同样可以使用“列表格”的方式自底向上求解:

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

#include

<

stdio.h

>

#include

<

string

.h

>

#define

N 100

int

a[N][N];

int

main(

void

) {

int

t , x , n , p , m , T;

while

(scanf(

"

%d%d%d%d

"

,

&

n,

&

p,

&

m,

&

T)

!=

EOF)

//

苹果树n,毛毛虫其实位置p,m分钟,终点位置T

{ memset(a,

0

,

sizeof

(a)); a[m][T]

=

1

;

for

(t

=

m

-

1

; t

>=

0

; t

--

) { a[t][

1

]

+=

a[t

+

1

][

2

];

for

(x

=

2

; x

<

n ; x

++

) a[t][x]

+=

a[t

+

1

][x

-

1

]

+

a[t

+

1

][x

+

1

]; a[t][n]

+=

a[t

+

1

][n

-

1

]; } printf(

"

%d\n

"

, a[

0

][p]); }

return

0

; }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值