cf1453F 二維DP 思維
阿新 • • 發佈:2020-12-11
cf1453F 二維DP 思維
題意
目前我們有一個序列,在第i個點可以走到[i + 1, i + a[i]]區間內的任意一點(也就是說如果a[i]是0,路就走不通了)
現在要求我們將一些位置置零,使得從1走到n只有一條路徑。輸出最小置零數量,保證輸入有解。
思路
- 因為n<=3000,所以嘗試二維動態規劃。首先設計狀態是最重要的一步,我們定義 \(F_{i,j}\) 為從1到i僅有一條路徑,且路徑中的點最遠到達不超過j,這種情況下的最小置零個數。
- 那麼顯然 \(F_{1,j}\) 全為0,答案為 \(F_{n,n}\)
- 從2開始計算,對於當前的i,我們列舉i - 1 ~ 1的所有點,如果有 \(j + a_j \ge i\)
其中cnt是從j + 1到i - 1所有的點中,能夠到達i的點的數量(就是說這些cnt個點都需要置零),由於我們是從i - 1到1的順序列舉的,所以cnt可以順帶記錄
AC程式碼
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> using namespace std; int ff[3005][3005], aa[3005]; int t, n; int main() { scanf("%d", &t); while (t--) { scanf("%d", &n); for (int i = 1; i <= n; ++i) { scanf("%d", &aa[i]); for (int j = 1; j <= n; ++j) { ff[i][j] = 99999999; } } for (int i = 1; i <= n; ++i) { ff[1][i] = 0; } for (int i = 2; i <= n; ++i) { int cnt = 0; for (int j = i - 1; j >= 1; --j) { if (j + aa[j] >= i) { ff[i][j + aa[j]] = min(ff[i][j + aa[j]], ff[j][i - 1] + cnt); ++cnt; } } for (int j = i + 1; j <= n; ++j) { ff[i][j] = min(ff[i][j - 1], ff[i][j]); } } printf("%d\n", ff[n][n]); } return 0; }