1.HDU 4540
简单DP
#include <cstdio> #include <iostream> using namespace std; int main() { // freopen("data3.txt", "r", stdin); int dp[30][20], pos[30][20]; int n, k; while (~scanf("%d%d", &n, &k)) { memset(dp, 0x7f, sizeof(dp)); for (int i = 0; i < n; i++) for (int j = 0; j < k; j++) scanf("%d", &pos[i][j]); for (int i = 0; i < k; i++) dp[0][i] = 0; for (int i = 1; i < n; i++) for (int j = 0; j < k; j++) { for (int d = 0; d < k; d++) dp[i][j] = min(dp[i][j], dp[i - 1][d] + abs(pos[i - 1][d] - pos[i][j])); } int ans = 0x3fffffff; for (int i = 0; i < k; i++) ans = min(ans, dp[n - 1][i]); printf("%d ", ans); } return 0; }
2.HDU 1078
记忆化,类似树从根节点向上dp
#include<cstdio> #include <iostream> #include<cstring> #include<cmath> using namespace std; #define N 105 int dir[4][2] = { 1, 0, -1, 0, 0, 1, 0, -1 }; int dp[N][N], map[N][N]; bool mark[N][N], vis[N][N]; int n, k; inline bool check(int x, int y) { return x >= 0 && x < n && y >= 0 && y < n; } void DP(int a, int b) { mark[a][b] = 1; vis[a][b] = 1; int x, y; for (int i = 0; i < 4; i++) { for (int j = 1; j <= k; j++) { x = a + dir[i][0] * j; y = b + dir[i][1] * j; if (check(x, y) && !vis[x][y] && map[x][y] > map[a][b]) { if (mark[x][y]) { dp[a][b] = max(dp[a][b], dp[x][y] + map[a][b]); } else { DP(x, y); dp[a][b] = max(dp[a][b], dp[x][y] + map[a][b]); } } } } if (dp[a][b] == 0) dp[a][b] = map[a][b]; vis[a][b] = 0; } int main() { // freopen("data3.txt", "r", stdin); int i, j; while (scanf("%d%d", &n, &k)) { if (n == -1 && k == -1) break; memset(mark, 0, sizeof(mark)); memset(dp, 0, sizeof(dp)); memset(vis, 0, sizeof(vis)); for (i = 0; i < n; ++i) { for (j = 0; j < n; ++j) { scanf("%d", &map[i][j]); } } mark[0][0] = 1; DP(0, 0); printf("%d ", dp[0][0]); } return 0; }
3. 携程第二场
二维背包的思想,枚举每段长度,来维护dp[i][j]表示两段长度分别为 i 和 j 能否被拼出来。最后通过dp[i][j]为1的判断形成三角形和最大的面积。
#include <cstdio> #include <iostream> #include <cstring> #include <cmath> using namespace std; double deal(double a, double b, double c) { double p = (a + b + c) / 2.0; return sqrt(p * (p - a) * (p - b) * (p - c)); } bool check(int a, int b, int c) { if (a + b <= c) return 0; if (a + c <= b) return 0; if (b + c <= a) return 0; return 1; } int f[1005][1005]; int dp[50]; int main() { int n; while (scanf("%d", &n) == 1) { if (n == 0) break; int totlen = 0; memset(f, 0, sizeof(f)); for (int i = 0; i < n; i++) { scanf("%d", &dp[i]); totlen += dp[i]; } f[0][0] = 1; for (int i = 0; i < n; i++) { for (int k = 1000; k >= 0; k--) { for (int j = k; j >= 0; j--) { if (k - dp[i] >= 0 && f[k - dp[i]][j]) f[k][j] = 1; if (j - dp[i] >= 0 && f[k][j - dp[i]]) f[k][j] = 1; } } } double ans = 0; for (int i = 0; i <= 1000; i++) { for (int j = 0; j <= i; j++) { if (f[i][j] && check(i, j, totlen - i - j)) ans = max(ans, deal(i, j, totlen - i - j)); } } if (!ans) puts("-1"); else printf("%d ", (int) (ans * 1000) / 10); } return 0; }