問題分析
心得體會
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...