DP训练

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\n", 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\n", 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\n", (int) (ans * 1000) / 10);
    }
    return 0;
}

 

 

posted @ 2013-12-01 10:57  匡时@下一站.info  阅读(254)  评论(0编辑  收藏  举报