kuangbin专题十二:基础DP1
先跳过几章,换换口味。
思路:经典DP题。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 1e6 + 5; int s[maxn], dp[maxn], pre[maxn]; int main(){ int n, m; while(scanf("%d%d", &m, &n) != EOF){ memset(dp, 0, sizeof(dp)); memset(pre, 0, sizeof(pre)); for(int i = 1; i <= n; i++) scanf("%d", s + i); int maxx; for(int group = 1; group <= m; group++){ maxx = -0x3f3f3f3f; for(int i = group; i <= n; i++){ dp[i] = max(dp[i - 1] + s[i], pre[i - 1] + s[i]); pre[i - 1] = maxx; maxx = max(maxx, dp[i]); } } printf("%d\n", maxx); } return 0; }
HDU1029 Ignatius and the Princess IV
思路:就喜欢DP题,代码量小。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int main(){ int n; while(scanf("%d", &n) != EOF){ int cnt = 0, num = -1, val; while(n--){ scanf("%d", &val); if(num != val){ if(cnt > 0) cnt--; else cnt = 1, num = val; } else cnt++; } printf("%d\n", num); } return 0; }
思路:一个盒子放6次。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 1e3 + 5; int dp[maxn]; struct Cube{ int w, l, h; } cube[maxn]; bool cmp(Cube &x, Cube &y){ if(x.w == y.w) return x.l < y.l; return x.w < y.w; } int main(){ int n, T = 0; while(scanf("%d", &n) && n){ int idx = 0; for(int i = 0; i < n; i++){ int x, y, z; scanf("%d%d%d", &x, &y, &z); cube[idx++] = {x, y, z}; cube[idx++] = {x, z, y}; cube[idx++] = {y, x, z}; cube[idx++] = {y, z, x}; cube[idx++] = {z, x, y}; cube[idx++] = {z, y, x}; } sort(cube, cube + idx, cmp); memset(dp, 0, sizeof(dp)); for(int i = 0; i < idx; i++) dp[i] = cube[i].h; for(int i = 0; i < idx; i++) for(int j = i - 1; j >= 0; j--){ if(cube[i].w > cube[j].w && cube[i].l > cube[j].l) dp[i] = max(dp[i], dp[j] + cube[i].h); } int ans = 0; for(int i = 0; i < idx; i++) if(dp[i] > ans) ans = dp[i]; printf("Case %d: maximum height = %d\n", ++T, ans); } return 0; }
思路:状态压缩DP。这种题目我第一次见到是我弟出给我的,欺负我这个老同志,来骗,来偷袭。
HDU1087 Super Jumping! Jumping! Jumping!
思路:最长子序列。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 1005; int num[maxn], dp[maxn]; int main(){ int n; while(scanf("%d", &n) && n){ for(int i = 0; i < n; i++) scanf("%d", &num[i]); for(int i = 0; i < n; i++){ dp[i] = num[i]; for(int j = 0; j < i; j++) if(num[i] > num[j]) dp[i] = max(dp[i], dp[j] + num[i]); } int ans = 0; for(int i = 0; i < n; i++) ans = max(ans, dp[i]); printf("%d\n", ans); } return 0; }
思路:基础背包。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 10005; int dp[maxn]; int main(){ int T; scanf("%d", &T); while(T--){ int E, F, P, W, N, tot; scanf("%d%d%d", &E, &F, &N); tot = F - E; memset(dp, 0x3f, sizeof(dp)); dp[0] = 0; while(N--){ scanf("%d%d", &P, &W); for(int i = W; i <= tot; i++) if(dp[i] > dp[i - W] + P) dp[i] = dp[i - W] + P; } if(dp[tot] == 0x3f3f3f3f) printf("This is impossible.\n"); else printf("The minimum amount of money in the piggy-bank is %d.\n", dp[tot]); } return 0; }
思路:從前往後,咦,輸入怎麽變成繁體了。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 100005; int dp[maxn][11]; int main(){ int n; while(scanf("%d", &n) && n){ int x, T, maxT = 0; memset(dp, 0, sizeof(dp)); for(int i = 1; i <= n; i++){ scanf("%d%d", &x, &T); dp[T][x] += 1; maxT = max(maxT, T); } for(int i = maxT; i >= 0; i--) for(int j = 0; j <= 10; j++){ int tmp = 0; for(int k = -1; k <= 1; k++) if(k + j >= 0 && k + j <= 10) tmp = max(tmp, dp[i + 1][j + k]); dp[i][j] += tmp; } printf("%d\n", dp[0][5]); } return 0; }
思路:模板题。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 2005; int dp[maxn]; int single[maxn], couple[maxn]; int main(){ int T; scanf("%d", &T); while(T--){ int k; scanf("%d", &k); for(int i = 1; i <= k; i++) scanf("%d", &single[i]); for(int i = 2; i <= k; i++) scanf("%d", &couple[i]); // dp dp[1] = single[1]; for(int i = 2; i <= k; i++){ dp[i] = min(dp[i - 1] + single[i], dp[i-2] + couple[i]); } int h = 8 + dp[k] / 3600, m = (dp[k] / 60) % 60, s = dp[k] % 60; printf("%02d:%02d:%02d ", h, m, s); if(h <= 12) printf("am\n"); else printf("pm\n"); } return 0; }
思路:考虑每个发射高度的最多发射数量。
#include<iostream> #include<cstring> using namespace std; const int maxn = 3e4 + 5; int dp[maxn], h[maxn]; int main(){ int n; while(cin >> n){ for(int i = 1; i <= n; i++) cin >> h[i], dp[i] = 1; int ans = 0; for(int i = 1; i <= n; i++){ for(int j = i + 1; j <= n; j++) if(h[i] < h[j]) dp[j] = max(dp[j], dp[i] + 1); ans = max(dp[i], ans); } cout << ans << endl; } return 0; }
思路:LIS,注意体重相同的情况。
#include<iostream> #include<algorithm> #include<stack> #include<stdio.h> using namespace std; const int maxn = 1e4 + 5; int dp[maxn]; struct Mouse{ int w, s, id; } mice[maxn]; bool cmp(Mouse& a, Mouse& b){ if(a.w == b.w) return a.s > b.s; return a.w < b.w; } int main(){ int cnt = 0; while (cin >> mice[cnt].w >> mice[cnt].s) { mice[cnt].id = cnt; dp[cnt++] = 1; } sort(mice, mice + cnt, cmp); int reslen = 0; for (int i = 0; i < cnt; i++) { for (int j = i + 1; j < cnt; j++) { if (mice[i].w != mice[j].w && mice[i].s > mice[j].s) { dp[j] = max(dp[j], dp[i] + 1); } } reslen = max(reslen, dp[i]); } stack<int> s; int current; for (int i = cnt - 1; i >= 0; i--) { if (s.empty()) { if (dp[i] == reslen) { current = i; s.push(mice[i].id); } } else { if (dp[current] - 1 == dp[i] && mice[i].w != mice[current].w && mice[i].s > mice[current].s) { current = i; s.push(mice[i].id); } } } cout << reslen << endl; while(s.size()) { cout << s.top() + 1 << endl; s.pop(); } return 0; }
思路:最长公共子序列。
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int maxn = 1005; int dp[maxn][maxn]; int main(){ string s1, s2; while (cin >> s1 >> s2) { memset(dp, 0, sizeof(dp)); for (int i = 0; i < s1.length(); i++) { for (int j = 0; j < s2.length(); j++) { if (s1[i] == s2[j]) dp[i+1][j+1] = dp[i][j] + 1; else { dp[i+1][j+1] = max(dp[i+1][j+1], dp[i][j]); dp[i+1][j+1] = max(dp[i+1][j+1], dp[i+1][j]); dp[i+1][j+1] = max(dp[i+1][j+1], dp[i][j+1]); } } } cout << dp[s1.length()][s2.length()] << endl; } return 0; }
思路:暴力DP。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int maxn = 1005; int n, x, y, mx; struct Seg{ int x1, x2, h; } seg[maxn]; int Conn[maxn][2]; int dp[maxn][2]; bool fall(Seg& s, int xx, int hh){ if(hh - s.h > mx) return false; return s.x1 <= xx && xx <= s.x2; } bool cmp(const Seg& a, const Seg& b){ return a.h > b.h; } int main(){ int t; cin >> t; while(t--){ cin >> n >> x >> y >> mx; for(int i = 0; i < n; i++) cin >> seg[i].x1 >> seg[i].x2 >> seg[i].h; seg[n].x1 = seg[n].x2 = x, seg[n].h = y; sort(seg, seg + n + 1, cmp); memset(dp, 0x3f, sizeof(dp)); memset(Conn, 0, sizeof(Conn)); dp[0][0] = dp[0][1] = 0; for(int i = 0; i <= n; i++){ for(int j = i + 1; j <= n; j++){ if(fall(seg[j], seg[i].x1, seg[i].h)){ dp[j][0] = min(dp[j][0], dp[i][0] + seg[i].x1 - seg[j].x1); dp[j][1] = min(dp[j][1], dp[i][0] + seg[j].x2 - seg[i].x1); Conn[i][0] = 1; break; } } for(int j = i + 1; j <= n; j++){ if(fall(seg[j], seg[i].x2, seg[i].h)){ dp[j][0] = min(dp[j][0], dp[i][1] + seg[i].x2 - seg[j].x1); dp[j][1] = min(dp[j][1], dp[i][1] + seg[j].x2 - seg[i].x2); Conn[i][1] = 1; break; } } } int res = 0x3f3f3f3f; for(int i = n; i >= 0; i--){ if(seg[i].h > mx) break; if(!Conn[i][0]) res = min(res, dp[i][0]); if(!Conn[i][1]) res = min(res, dp[i][1]); } res += y; cout << res << endl; } return 0; }
POJ2533 Longest Ordered Subsequence
思路:模板题。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int maxn = 1005; int a[maxn]; int dp[maxn]; int main(){ int n; cin >> n; for(int i = 1; i <= n; i++){ cin >> a[i]; dp[i] = 1; } int res = 0; for(int i = 1; i <= n; i++){ for(int j = i + 1; j <= n; j++) if(a[i] < a[j]) dp[j] = max(dp[i] + 1, dp[j]); res = max(res, dp[i]); } cout << res << endl; return 0; }
思路:区间DP。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int maxn = 2005; int ary[maxn]; int dp[maxn][maxn]; int main(){ int n; cin >> n; for(int i = 1; i <= n; i++) cin >> ary[i]; for(int i = 1; i <= n; i++) dp[i][i] = ary[i] * n; for(int i = 1; i < n; i++){ for(int j = 1; j + i <= n; j++){ dp[j][j + i] = max(dp[j+1][j+i] + ary[j] * (n - i), dp[j][j+i-1] + ary[j+i] * (n - i)); } } cout << dp[1][n] << endl; return 0; }
思路:记忆化搜索。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int maxn = 105; int n, k; int dx[] = {1, 0, -1, 0}, dy[] = {0, 1, 0, -1}; int mm[maxn][maxn]; int dp[maxn][maxn]; bool inRange(int x, int y){ return x >= 0 && y >= 0 && x < n && y < n; } void search(int x, int y){ for(int i = 0; i < 4; i++){ for(int j = 1; j <= k; j++){ int nx = x + j * dx[i], ny = y + j * dy[i]; if(inRange(nx, ny) && mm[x][y] < mm[nx][ny]){ if(!dp[nx][ny]) search(nx, ny); dp[x][y] = max(dp[x][y], dp[nx][ny] + mm[x][y]); } } } dp[x][y] = max(dp[x][y], mm[x][y]); } int main(){ while(cin >> n >> k && n != -1){ memset(dp, 0, sizeof(dp)); for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) cin >> mm[i][j]; search(0, 0); cout << dp[0][0] << endl; } return 0; }
思路:二维DP。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int maxn = 1005; int n; char mm[maxn][maxn]; int dp[maxn][maxn]; int main(){ while(cin >> n && n){ for(int i = 0; i < n; i++) for(int j = 0; j < n; j++){ cin >> mm[i][j]; dp[i][j] = 1; } for(int i = 1; i < n; i++){ for(int j = 0; j < n-1; j++){ int len = dp[i-1][j+1]; int k; for(k = 1; k <= len; k++) if(mm[i-k][j] != mm[i][j+k]){ break; } dp[i][j] = k; } } int res = 0; for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) res = max(res, dp[i][j]); cout << res << endl; } return 0; }
思路:离散化。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int maxn = 1e3+5; int n, m, r; int dp[maxn]; struct Interval{ int st, ed, eff; } intv[maxn]; bool cmp(const Interval& a, const Interval& b){ if(a.st == b.st) return a.ed < b.ed; return a.st < b.st; } int main(){ cin >> n >> m >> r; for(int i = 0; i < m; i++){ cin >> intv[i].st >> intv[i].ed >> intv[i].eff; intv[i].ed += r; } sort(intv, intv + m, cmp); for(int i = 0; i < m; i++){ dp[i] = intv[i].eff; for(int j = 0; j < i; j++) if(intv[j].ed <= intv[i].st) dp[i] = max(dp[i], dp[j] + intv[i].eff); } int res = 0; for(int i = 0; i < m; i++) res = max(res, dp[i]); cout << res << endl; return 0; }
思路:二维dp,注意别写成三维dp。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int maxn = 2e3+5; int n; int A[maxn], B[maxn], C[maxn]; long long dp[maxn][maxn][2]; bool cmp(int a, int b){ return a > b; } int main(){ scanf("%d", &n); for(int i = 0; i < n; i++){ scanf("%d", A+i); B[i] = C[i] = A[i]; } sort(B, B + n); sort(C, C + n, cmp); memset(dp, 0x3f, sizeof(dp)); dp[0][0][0] = abs(A[0] - B[0]); dp[0][0][1] = abs(A[0] - C[0]); for(int i = 1; i < n; i++){ dp[0][i][0] = min(dp[0][i-1][0], (long long)abs(A[0] - B[i])); dp[0][i][1] = min(dp[0][i-1][1], (long long)abs(A[0] - C[i])); dp[i][0][0] = dp[i-1][0][0] + abs(A[i] - B[0]); dp[i][0][1] = dp[i-1][0][1] + abs(A[i] - C[0]); } for(int i = 1; i < n; i++){ for(int j = 1; j < n; j++){ dp[i][j][0] = min(dp[i-1][j][0] + abs(A[i] - B[j]), dp[i][j-1][0]); dp[i][j][1] = min(dp[i-1][j][1] + abs(A[i] - C[j]), dp[i][j-1][1]); } } long long res = 0x3f3f3f3f; for(int i = 0; i < n; i++) res = min(res, dp[n-1][i][0]), res = min(res, dp[n-1][i][1]); printf("%lld\n", res); return 0; }