這幢古老的建築是乙個藝術館,它珍藏著上百件繪畫、雕塑以及其他藝術品,就連建築本身也是一件藝術。但是,歲月並不在乎它的精緻與美麗,時光在漸漸剝奪著這幢木屋的生命。終於,在乙個月色昏暗的夜晚,它著火了。
藝術館是一幢兩層的小樓,每一層有n個房間,每個房間中收藏的藝術品的價值都可以用乙個正整數來表示。下面是乙個n=4的例子。
在這個例子中,二層樓的第四個房間中藝術品的價值最大,為60。而一層樓的第四個房間中藝術品的價值僅為20。
在消防隊員火速趕到的時候,火勢已經蔓延了整個建築,消防隊員們觀察每個房間中的火勢,將它們分別用乙個正整數來表示。在上面的例子中,各房間中的火勢可能如下。
你可以看到,二層樓的第四個房間中火勢最強,為70。而一層樓的第三個房間中火勢較弱,為20。
由於火情緊急,消防隊員們準備使用一種新型的滅火器。這種滅火器只能發射k次,每次發射將覆蓋乙個矩形的區域(矩形的高度可以是1也可以是2)。它的威力巨大,所到之處不但火焰會被撲滅,就連同在一處的藝術品也難以倖免。因此,如何善用這種滅火器成了最大的問題。
乙個例子:如果滅火器的一次發射覆蓋了下圖陰影所示的2×2矩形區域,那麼這四個房間的火勢和藝術品價值都將成為0。
給出藝術館每層的房間數n和滅火器的發射次數k,以及每個房間中藝術品的價值和火勢,你需要決定滅火器每次應該怎樣發射(也可以不發射),才能將這次火災的損失降到最低限度。這個損失用你所摧毀的藝術品的總價值,加上剩餘的火勢總值(這些火焰將需要消防隊員們親身去撲滅)來衡量。
輸入檔案的第一行有兩個整數n(1 <= n <= 100)、k(1 <= k <= 10),分別表示藝術館中每層的房間數和滅火器的發射次數。
接下來的兩行每行有n個整數,其中第4-i行的第j個整數vi,j表示的是第i層第j個房間中藝術品的價值(1 <= i <= 2,1 <= j <= n,1 <= vi,j <= 10000)。
再接下來的兩行每行也有n個整數,其中第6-i行的第j個整數fi,j表示的是第i層第j個房間中的火勢(1 <= i <= 2,1 <= j <= n,1 <= fi,j <= 10000)。
計算最小的損失。
樣例輸入:
4 140 50 30 60
30 30 40 20
50 40 50 70
40 50 20 30
4 240 50 30 60
30 30 40 20
50 40 50 70
40 50 20 30
4 340 50 30 60
30 30 40 20
50 40 50 70
40 50 20 30
4 440 50 30 60
30 30 40 20
50 40 50 70
40 50 20 30
4 540 50 30 60
30 30 40 20
50 40 50 70
40 50 20 30
4 140 50 30 60
30 30 40 200
50 40 50 70
40 50 20 30
3 110 30 10
10 10 30
30 10 30
30 30 10
樣例輸出:
題意: 在乙個2*n的矩陣中選取k個子矩陣, 使得損失最小. 子矩陣的大小可以使1*l or 2*l, 其中1和2
表示矩陣高度, l表示矩陣長度(1<=l<=n);
解題思路: (想了2天, 終於想明白!!!)
1. 題目給出2個權值, val價值和f火勢, 最後結果: min(摧毀價值+剩餘火勢), 滅火器最多發射
k次, 每次滅火的區域大小1*l or 2*l.
2. 開始想到狀態是dp[i][j][k]表示第1行前i列和第2行前j列選擇了k個矩陣還能獲取最小損失.
但是在狀態轉移時, 無法確定上乙個狀態的選擇情況, 狀態方程寫不出. 改了一種方法:
設: dp[k][i][j]表示前i列中選取了k個矩形, 第i列的選取情況是j, 此時還能獲取的最小
損失.(1). 狀態方程: dp[k][i][j] = min( dp[i+1][p][nextk]+getloss(i+1, p) )
其中p表示i+1列的選取情況, nextk表示k+1 or k不變;
(2). 每列有4種選取情況: 0: 上下層都不用滅火器
1: 只是上層使用滅火器
2: 只是下層使用滅火器
3: 上下層都使用滅火器
這裡我們增設一種情況: 4: 當前列上下層同前一列上下層都使用滅火器.
因為會出現一種情況: 當j = 3時, p = 1 or 2, 如下圖(舉例p = 1)
中間列為j(當前), 最後一列為p(下一列), 顯然第一種情況下, 因為第一列
選取情況是2造成, 當p = 1時, 雖然當前列與下一列選取情況不同應該nextk
= k+1,但是前一列的結果造成nextk = k. 第二種情況是最想看見的, 為了
區別第一種情況, 所以增設了一種選取情況.
(3). nextk = (k+1) or nextk = k, 顯然滿足 p == 0 || j == p || j == 4
當前列上下層都不使用滅火器, 當前列狀態與前一列選取情況相同, 上一列
已經標記為特殊狀態要求當前列上下層同前一列上下層都使用滅火器. 此時
nextk = k.
3. 從設的狀態可以知道是用向前遞推法, 結果dp(0, 0, 0); 記憶化搜尋即可.
**:#include
#include
#include
using namespace std;
#define max 105
const int inf = (1<<29);
int n, k;
int val[3][max], f[3][max];
int dp[12][max][5];
int result;
inline int min(int a, int b)
int getloss(int i, int j) //0:上下不用, 1:上用, 2:下用, 3:滅火器覆蓋最少1個小矩形, 4:覆蓋至少2個矩形
int dp(int k, int i, int j)
return dp[k][i][j] = ans;
}int main()
for(i = 1; i <= 2; ++i)
memset(dp, -1, sizeof(dp));
result = dp(0, 0, 0);
printf("%d\n", result);
}return 0;}
acm 動態規劃
學習參考 就是倒推 尋找遞推式 難點 然後用陣列將資料計算出來 最後直接呼叫得到答案 01揹包問題 for i 0 i 例題一 洛谷oj 開心的金明 include include using namespace std const int max 100001 long long dp max i...
《動態規劃》 ACM 動態規劃例題詳解
描述 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 圖1 圖1給出了乙個數字三角形。從三角形的頂部到底部有很多條不同的路徑。對於每條路徑,把路徑上面的數加起來可以得到乙個和,你的任務就是找到最大的和。注意 路徑上的每一步只能從乙個數走到下一層上和它最近的左邊的那個數或者右邊的那個數。輸...
ACM 動態規劃筆記
2.解決動態規劃問題,要先找出動態轉移方程來,動態轉移方程怎麼找呢?首先得定好,用哪幾個因子,可以明確的表示好乙個狀態,然後,再通過樣例或者特例或者硬想,找出子問題和父問題的關係,或者說,子問題怎麼push,可以影響到父問題?我感覺可以放開思路想,放心大膽的想,假設你不會動態規劃,讓你暴力搜尋,你會...