問題描述
如果一個自然數N的K進製表示中任意的相鄰的兩位都不是相鄰的數字,那麼我們就說這個數是K好數。求L位K進制數中K好數的數目。例如K = 4,L = 2的時候,所有K好數爲11、13、20、22、30、31、33 共7個。由於這個數目很大,請你輸出它對1000000007取模後的值。
輸入格式
輸入包含兩個正整數,K和L。
輸出格式
輸出一個整數,表示答案對1000000007取模後的值。
樣例輸入
4 2
樣例輸出
7
數據規模與約定
對於30%的數據,KL <= 106;
對於50%的數據,K <= 16, L <= 10;
對於100%的數據,1 <= K,L <= 100。
題解:
首先解釋一下,
動態規劃:將待求的問題分解成若干子問題,先求解子問題然後從這些子問題中獲得原問題的解。
與分治法的區別:動態規劃分解的子問題可能不是相互獨立的。
基本要素:1.最優子結構,2,重疊子問題
最優子結構:當問題的最優解包含了其子問題的最優解的時候,稱其具有最優子結構
重疊子問題:每次產生的子問題並不都是新的問題,有些子問題被重複計算多次
自下往上:
備忘錄算法:(自頂向下)
狀態壓縮:
步驟:1.劃分階段 2.正確選擇狀態變量 3.確定決策變量以及允許決策的集合
4.確定狀態轉移方程 5.確定階段指標函數和最優指標函數,建立動態規劃基本方程
一般情況下,只要能做到備忘錄算法這一步,基本就ac了。
其次,說一下這道題,首先劃分階段,L位數從 最低位到最高位分爲不同的階段,狀態變量就是位置i了,表示在第幾位,
決策變量就是的d[i][j]了即表示將i位置的值置爲j時的k好數的個數,狀態轉移方程:由分析,其狀態轉移方程從最低+1位開始,
d[i][j]= ∑d[i-1][r](r!=j+1&&r!=j-1&&0<=r<=k-1) 最高位j!=0,需特殊處理;其初始條件爲d[0][j]=1;不受約束。
於是乎代碼如下:
import java.util.Scanner;
//k好數 dp
public class Main {
final static int maxn=100;
final static int M=1000000007;
static int d[][]=new int[maxn+5][maxn+5];//d[i][j]表示將i位置的值置爲j時的k好數的個數
//由分析,其狀態轉移方程從最低+1位開始,d[i][j]= ∑d[i-1][r](r!=j+1&&r!=j-1&&0<=r<=k-1)
//最高位j!=0,需特殊處理
//其初始條件爲d[0][j]=1;不受約束
public static void main(String[] args) {
Scanner cin= new Scanner(System.in);
int k,l;
k=cin.nextInt();
l=cin.nextInt();
for(int j=0;j<k;j++) d[0][j]=1;
for(int i=1;i<l;i++)//i=0已經初始化過了
{
for(int j=0;j<k;j++)//求第i個位置放置每一個值時d[i][j]的大小;
{
d[i][j]=0;
for(int r=0;r<k;r++)
{
if(r!=j+1&&r!=j-1)//狀態轉移表達式要滿足的條件
{
d[i][j]+=d[i-1][r];
d[i][j]%=M;
}
}
}
}
int ans=0;
for(int j=1;j<k;j++)//最後一位的情況不包括0
{
ans+=d[l-1][j];
ans%=M;
}
System.out.println(ans);
}
}
測試樣例:
詳細記錄 |
|
感受:
1.作爲第一道用JavaAC的動態規劃題,感覺還是不錯的。以前總是感覺java和c++比要慢的多,很多題用c++實現都過了,但用java實現就是超時,抓狂,,, 但是現在ac了之後感覺其實java更鍛鍊自己的能力,讓自己更加懂得優化自己的代碼。
2.還有就是以後寫動態規劃題的時候注意理思路,套框架,從根本上理解並掌握動態規劃的精髓。