再次總結一些比較經典的在矩陣中確定乙個起始狀態和結束狀態, 問從起始到結束中走過的數要得到, 問最小(大), 路徑輸出等問題. 這些問題都可以轉化為dp模型來解決. 下面以一些我做過的題進行分析.
入門級: 51nod - 1083
問題: 給定乙個二維矩陣, 問從左上角走到右下角可以取到的最大值是多少. 每次只能往下或者往右走.
這道題就非常簡單了, dp[i][j] 代表走到(i, j)這個點的最大值是多少, 轉移方程就是
dp[i][j] = dp[i-1][j] + dp[i][j-1]; o(n^2)的複雜度.
ac code
const int maxn = 5e2+5;
int a[maxn][maxn], dp[maxn][maxn];
void solve()
}for (int i = 1 ; i <= n ; i ++)
}cout << dp[n][n] << endl;
}
變形題 洛谷p1002
題意: 就是在乙個二維矩陣中, 有一匹馬, 馬一次能跳到的點是他的控制點, 問從(0, 0)出發到達所給的終點的路徑有多少條. 每次只能向下或者右走.
依舊dp, dp[i][j] 代表到達這個點的路徑條數, 那麼它依舊只能被上走兩個進行更新, 只不過我們需要處理下馬搜控制的點判一下不進行更新即可. 轉移方程類似
ac code
const
int maxn = 50+5;
int a[maxn][maxn];
ll dp[maxn][maxn];
int dx = ;
int dy = ;
void solve()
a[rx][ry] = -1;
dp[0][0] = 1;
for (int i = 0 ; i <= 20 ; i ++)
if (dp[ex][ey]) break;
}printf("%lld\n", dp[ex][ey]);
}
變形二: uva - 10285
題意: 還是乙個二維矩陣, 可以從任意乙個點出發或者結束, 對應上面的點代表該點的海波高度, 每次只能向海拔高度低的走, 問可以走的最長的路有多長. 可以往四個方向走.
思路: 還是dp, dp[i][j] 代表走到這個點的最長路徑是多少, 那麼因為起始點可以任意, 所以我們需要進行一波預處理, 即我們把矩陣中的每乙個數和位置先取出來, 然後按照從小到大進行排序, 每次取出來乙個就進行在原圖上的dp, 即判斷四個方向中如果有比當前點小的點並且可以進行更新(即更優路徑), 那麼我們就更新這個點即可, 最後在所有的點中取乙個max即可
ac code
const
int maxn = 1e2+5;
int dx = ;
int dy = ;
struct node
}e[maxn*maxn];
int a[maxn][maxn], dp[maxn][maxn];
void solve()
; }
}sort(e+1, e+1+k); int ans = 0;
for (int i = 1 ; i <= k ; i ++) }}
cout
<< s << ": "
<< ans << endl;
}}
經典問題 : uva116
(這道題非常經典, 一定要記住這道題!)
題意: 還是乙個二維矩陣, 每個點上有數, 從這個矩陣的第一列的任意位置出發到達最後一列的任意位置結束, 每次可以向下一列的上面一行, 當前行, 下面一行走, 並且注意在第一行時向上面一行走是走到最後一行, 同理最後一行也是, 問能取到的最小值是多少, 並且輸出路徑, 即每一列的行數, 如果有多解, 那麼輸出字典序最小的答案.
思路: 跟矩陣取數有點類似, 所以我們可以設dp[i][j]代表走到這個(i, j)的最小值是多少, 注意到最後要輸出路徑, 當然很簡單記錄一下此時的狀態從哪個狀態轉移過來的即可, (但是我正著寫死活過不了, 希望路過的大神貼乙份正著寫的**給我學習學習…), 所以我們倒著推, 即從結束狀態往起始狀態推, 這樣答案肯定不會變的,然後我們處理好邊界問題即可, 和同時處理好字典序的問題, 詳情請看**實現:
ac code
const
int inf = 0x3f3f3f3f; //用這個可以直接mem
const ll inf = 1e18;
const
int mod = 1e9+7;
const
int maxn = 1e2+5;
int a[15][maxn], pre[15][maxn], dp[15][maxn];
int next[15][maxn];
int path[maxn];
void solve()
}int st = 1;
fill(dp, inf); int ans = inf;
for (int i = m ; i >= 1 ; i --) ;
if (j == 1) r[0] = n; // 處理邊界問題
if (j == n) r[2] = 1;
sort(r, r+3); // 這樣就可以保證字典序最小啦.
for (int k = 0 ; k < 3 ; k ++) }}
if (i == 1 && dp[j][i] < ans) ans = dp[j][i], st = j;
// 同樣我們行是從小列舉的, 這樣也就可以保證字典序樂.}}
printf("%d", st);
for (int i = 1 ; i < m ; i ++) // 列印路徑即可
printf("\n%d\n", ans);
}}
相似題: hdu - 5092
經典題的簡化, 幾乎和上面那道題一模一樣, 就是變成了從第一行到最後一行, 並且字典序最大, 最後輸出每一行的列數即可. 那麼會了上面那道, 這道就是隨便寫寫樂, 注意保持字典序最大即可.
這還是上海邀請賽的題, 應該是改編上面那道的, 所以記住經典模型是多麼重要的啊……. (當時我用的bfs寫的, 賊麻煩)
ac code
const
int inf = 0x3f3f3f3f; //用這個可以直接mem
const ll inf = 1e18;
const
int mod = 1e9+7;
const
int maxn = 100+5;
int a[maxn][maxn];
int dp[maxn][maxn], next[maxn][maxn];
void solve()
}int st = 1, mi = inf; fill(dp, inf);
for (int i = n ; i >= 1 ; i --)
if (dp[i+1][j] + a[i][j] < dp[i][j])
if (j - 1 >= 1 && dp[i+1][j-1] + a[i][j] < dp[i][j])
}if (i == 1 && dp[i][j] < mi) mi = dp[i][j], st = j;}}
printf("%d", st);
for (int i = 1 ; i < n ; i ++)
簡單DP 矩陣取數問題
乙個n n矩陣中有不同的正整數,經過這個格仔,就能獲得相應價值的獎勵,從左上走到右下,只能向下向右走,求能夠獲得的最大價值。例如 3 3的方格。1 3 3 2 1 3 2 2 1 能夠獲得的最大價值為 11。input 第1行 n,n為矩陣的大小。2 n 500 第2 n 1行 每行n個數,中間用空...
dp 更難的矩陣取數問題
題目 乙個m n矩陣中有不同的正整數,經過這個格仔,就能獲得相應價值的獎勵,先從左上走到右下,再從右下走到左上。第1遍時只能向下和向右走,第2遍時只能向上和向左走。兩次如果經過同乙個格仔,則該格仔的獎勵只計算一次,求能夠獲得的最大價值。例如 3 3的方格。1 3 3 2 1 3 2 2 1 能夠獲得...
多路dp 更難的矩陣取數問題
解題關鍵 1 注意i和j的最大取值都是n,k是i與j的和。2 空間卡的很緊,多一位都不行。轉移方程 dp max a a 通過觀察,可以消去乙個變數,從而 dp k 1 max a a 然後再將相同的處理掉即可 1 include2 using namespace std 3 typedef lon...