歷屆試題 地宮取寶
時間限制:1.0s 內存限制:256.0MB
問題描述
X 國王有一個地宮寶庫。是 n x m 個格子的矩陣。每個格子放一件寶貝。每個寶貝貼着價值標簽。
地宮的入口在左上角,出口在右下角。
小明被帶到地宮的入口,國王要求他只能向右或向下行走。
走過某個格子時,如果那個格子中的寶貝價值比小明手中任意寶貝價值都大,小明就可以拿起它(當然,也可以不拿)。
當小明走到出口時,如果他手中的寶貝恰好是k件,則這些寶貝就可以送給小明。
請你幫小明算一算,在給定的局面下,他有多少種不同的行動方案能獲得這k件寶貝。
輸入格式
輸入一行3個整數,用空格分開:n m k (1<=n,m<=50, 1<=k<=12)
接下來有 n 行數據,每行有 m 個整數 Ci (0<=Ci<=12)代表這個格子上的寶物的價值
輸出格式
要求輸出一個整數,表示正好取k個寶貝的行動方案數。該數字可能很大,輸出它對 1000000007 取模的結果。
樣例輸入
2 2 2
1 2
2 1
樣例輸出
2
樣例輸入
2 3 2
1 2 3
2 1 5
樣例輸出
14
話說這個題目意圖還是蠻明顯的,深搜完后返回所有滿足的解的個數,不過這個善意的題目,要想完全正確還是學需要在處理時注意很多方面。
首先,先來談第一個問題,寫出其狀態轉移方程,我們要求的解是從原點手握價值最大的寶物v開始經過不同的路徑到終點獲得K件寶物的路徑總數,我們姑且將此狀態記為
d(1,1,k(初始為0,還沒拿寶貝),-1(此時手上沒有寶物,值記為-1))
那么從此狀態出發,可以將其轉移為如下的決策
這里在補充說明用狀態轉移方程可以方便將原問題分解成若干個與原問題相同的子問題,且規模變小。
第二個問題,如果僅僅這樣的話,必然存在重復計算的問題,為此必須要采取記憶化搜索的方式,對於已經計算過的結點保存其值,就這條題目而言,必須要用一個四維數組保存,因為它的狀態跟位置,個數以及當前最大的寶物價值有關。當重復遍歷這個結點時,直接傳值。
第三個問題,細節決定成敗!!
1.類型用long long穩妥,因為即使MOD了,但是如果兩個數加起來還有可能超int。
2.我自己做的時候沒注意的一個小錯誤,導致最后始終不對的疏忽。我錯誤的把r[MAXN][MAXN][15][15]的初始化為了0,這絕對不正確,因為有可能以某種方式走的狀態就是無解,就是0,必須將初始值賦為-1。
3.對於有寶物的初始價值為-1,比較好的處理方式是,最后存放是第四維的下標后移一位
4.這里還要注意,k最多是13,不會超過這個值,所以第三維只要14就夠了
其它的就看代碼吧:

1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define MAXN 60 5 #define MOD %1000000007 6 using namespace std; 7 long long r[MAXN][MAXN][15][15];//保存狀態 8 long long map[MAXN][MAXN];//初始地圖 9 long long m,n,num; 10 long long dfs(long long i,long long j,long long k,long long v) 11 { 12 long long s=0,t; 13 if(r[i][j][k][v+1]!=-1) 14 return r[i][j][k][v+1]; 15 if(i==m&&j==n)//到達終點 16 { 17 if(k==num) 18 { 19 r[m][n][k][v+1]=1; 20 return r[m][n][k][v+1]; 21 } 22 else if(k==num-1&&map[m][n]>v) 23 { 24 r[m][n][k][v+1]=1; 25 return r[m][n][k][v+1]; 26 } 27 else 28 { 29 r[m][n][k][v+1]=0; 30 return r[m][n][k][v+1]; 31 } 32 } 33 else 34 { 35 if(map[i][j]>v) 36 { 37 t=map[i][j]; 38 if(i+1<=m) 39 s=(s+dfs(i+1,j,k+1,t)MOD+dfs(i+1,j,k,v)MOD)MOD; 40 if(j+1<=n) 41 s=(s+dfs(i,j+1,k+1,t)MOD+dfs(i,j+1,k,v)MOD)MOD; 42 } 43 else 44 { 45 if(i+1<=m) 46 s=(s+dfs(i+1,j,k,v)MOD)MOD; 47 if(j+1<=n) 48 s=(s+dfs(i,j+1,k,v)MOD)MOD; 49 } 50 r[i][j][k][v+1]=s MOD; 51 return r[i][j][k][v+1]; 52 } 53 } 54 int main() 55 { 56 // freopen("data.in","r",stdin); 57 // freopen("data.out","w",stdout); 58 memset(r,-1,sizeof(r)); 59 long long i,j,p,q; 60 cin>>m>>n>>num; 61 for(i=1;i<=m;i++) 62 for(j=1;j<=n;j++) 63 cin>>map[i][j]; 64 dfs(1,1,0,-1); 65 cout<<r[1][1][0][0]<<endl; 66 return 0; 67 }