week10 作業(動態規劃1)

2021-10-05 10:47:37 字數 3764 閱讀 4640

問題分析

心得體會

b - lis & lcs:

問題分析

心得體會

c - 拿數問題 ii:

問題分析

心得體會

題目簡述

東東在玩遊戲「game23」。

在一開始他有乙個數字n,他的目標是把它轉換成m,在每一步操作中,他可以將n乘以2或乘以3,他可以進行任意次操作。輸出將n轉換成m的操作次數,如果轉換不了輸出-1。

輸入/輸出格式

輸入格式:

輸入的唯一一行包括兩個整數n和m(1<=n<=m<=5*10^8).

輸出格式:

輸出從n轉換到m的操作次數,否則輸出-1.

樣例輸入樣例:

120 51840

輸出樣例:

7解題思路

由於2,3是互質的,所以最後的答案一定是唯一的,要麼是不可行,要麼是有且僅有一種方案使得原數變換成目標數。很明顯,我們每一步的決策都與前面的狀態有關係,因此使用動態規劃求解。乙個數最多有兩種轉移狀態:擴大2倍和擴大3倍,每次對這個狀態進行遞迴求解即可。由於最後返回的是次數,因此我們只要返回這兩種情況下的最大值即可(失敗返回-1,而如果有成功的方案,次數必定大於0)。

參考**

#include

#include

using

namespace std;

int n,m;

intgame23

(int n,

int time)

}int

main()

非常有意思的一道題目。雖然不難,但是很好的考察了動態規劃的相關知識,同時也讓我對動態規劃的演算法設計有了更深入的理解。

題目簡述

東東有兩個序列a和b。

他想要知道序列a的lis和序列ab的lcs的長度。

注意,lis為嚴格遞增的,即a1輸入/輸出格式

輸入格式:

第一行兩個數n,m(1<=n<=5,000,1<=m<=5,000)

第二行n個數,表示序列a

第三行m個數,表示序列b

輸出格式:

輸出一行資料ans1和ans2,分別代表序列a的lis和序列ab的lcs的長度

樣例輸入樣例:

6 71 5 2 6 8 7

2 3 5 6 9 8 4

輸出樣例:

4 3解題思路

做一道等於做兩道系列。考察兩種型別的問題。對於lis問題,定義f(i)為a1—ai所能取到的lis的長度,從f(2)開始依次向後遍歷,每次遍歷考察a中標號在遍歷點之前的點,如果發現該點大於f的標號點,那麼就記錄該點的位置。取滿足位置的點的f的最大值,當前點的值則記為最大值加1。最後只要輸出f中的最大值即可。lcs問題,定義g(i,j)為a1—ai和b1—bj的lcs長度。對a進行遍歷,在遍歷的過程中,對b進行遍歷,如果發現ai=bj,那麼g(i+1,j+1)就為g(i,j)+1,否則,g(i+1,j+1)就為g(i,j-1)和g(i-1,j)的最大值。最後的結果為g(n,m)。

參考**

#include

#include

#include

using

namespace std;

int a[

5050];

int b[

5050];

int f[

5050];

int g[

5050][

5050];

int n,m;

void

init()

intsolve1()

}}f[i]

=max_num+1;

if(f[i]

>max_sum) max_sum=f[i];}

return max_sum;

}int

solve2()

else}}

return g[n]

[m];

}int

main()

for(

int i=

1;i<=m;i++

)printf

("%d %d"

,solve1()

,solve2()

);return0;

}

lis和lcs問題是動態規劃的兩個經典問題。lis問題的解決思路還是比較好想的,然而lcs由於涉及到兩個數列,所以想起來比較的抽象,但是仔細想想,其實也就是增加了乙個維度,需要額外儲存一些資訊。所以,這個題也給我在多個變數的動態規劃問題上的思路上積累了經驗。

題目簡述

yjq 上完第10周的程式設計思維與實踐後,想到乙個絕妙的主意,他對拿數問題做了一點小修改,使得這道題變成了 拿數問題 ii。

給乙個序列,裡邊有 n 個數,每一步能拿走乙個數,比如拿第 i 個數, ai = x,得到相應的分數 x,但拿掉這個 ai 後,x+1 和 x-1 (如果有 aj = x+1 或 aj = x-1 存在) 就會變得不可拿(但是有 aj = x 的話可以繼續拿這個 x)。求最大分數。

本題和課上講的有些許不一樣,但是核心是一樣,需要你自己思考。

輸入/輸出格式

輸入格式:

第一行包含乙個整數 n (1 ≤ n ≤ 105),表示數字裡的元素的個數

第二行包含n個整數a1, a2, …, an (1 ≤ ai ≤ 105)

輸出格式:

輸出乙個整數:n你能得到最大分值。

樣例輸入樣例:

91 2 1 3 2 2 2 2 3

輸出樣例:

10解題思路

由於對拿數機制的更改,導致該拿數問題變成了在取乙個數之後,會不同程度的增加若干不能選的數的形式,這樣不能直接使用動態規劃求解。然而仔細分析可以發現,在此機制下,選擇乙個數之後,陣列中的其他與該數相同的數的選擇不受影響,但是其他與該數相鄰的數是不能選的,那麼,如果我們將輸入資料的數及其個數統計出,構成乙個新序列,這樣問題就又轉化成了乙個普通的拿數問題了。唯一的不同點是:此時選出乙個數後,增加的分數是對應的數值與數量的乘積。這樣利用普通的動態規劃即可解決。

參考**

#include

#include

#include

using

namespace std;

int max_num;

int min_num;

int m;

int sum_num[

100050];

long

long dp[

100050];

void

init()

long

long

solve

(int pos)

else}}

intmain()

printf

("%lld"

,solve

(max_num));

return0;

}

乙個拿數問題的變體,雖然一上來感覺無從下手,但是通過一步小小的轉化過程,即可轉換為普通的拿數問題。就我個人而言,我感覺在做這個題的時候我的思路還是很清晰的。自我感覺還是不錯的。問題轉化能力也是需要強化訓練的。另外,資料範圍問題還是要注意的,這次又被坑了啊啊啊啊啊!!!!

week10 作業 動態規劃(一)

東東在玩遊戲 game23 在一開始他有乙個數字n,他的目標是把它轉換成m,在每一步操作中,他可以將n乘以2或乘以3,他可以進行任意次操作。輸出將n轉換成m的操作次數,如果轉換不了輸出 1。輸入的唯一一行包括兩個整數n和m 1 n m 5 10 8 輸出從n轉換到m的操作次數,否則輸出 1.120 ...

week10作業 動態規劃(一)

b lis lcs c 拿數問題 ii a 簽到題 題目要求 東東在玩遊戲 game23 在一開始他有乙個數字n,他的目標是把它轉換成m,在每一步操作中,他可以將n乘以2或乘以3,他可以進行任意次操作。輸出將n轉換成m的操作次數,如果轉換不了輸出 1。input 輸入的唯一一行包括兩個整數n和m 1...

week10作業簽到

東東在玩遊戲 game23 在一開始他有乙個數字n,他的目標是把它轉換成m,在每一步操作中,他可以將n乘以2或乘以3,他可以進行任意次操作。輸出將n轉換成m的操作次數,如果轉換不了輸出 1。輸入的唯一一行包括兩個整數n和m 1 n m 5 10 8 輸出從n轉換到m的操作次數,否則輸出 1.samp...