【四边形】HDU 2829 Lawrence

通道

题意:有一段铁路有n个站,每个站可以往其他站运送粮草,现在要炸掉m条路使得粮草补给最小,粮草补给的公式是将每个站能收到的粮草的总和

思路:dp[i][j]表示到j为止的前面炸了i条路的得到最小总数,cost[i][j+1]>cost[i][j],单调递减,满足。

代码:

#include <cstdio>
#include <cstring>

const int MAX_N = 1007;

typedef long long ll;

template <class T>
inline bool rd(T &ret) {
    char c; int sgn;
    if(c = getchar() , c == EOF) return false;
    while(c != '-' && (c < '0' || c > '9')) c = getchar();
    sgn = (c == '-') ? -1 : 1;
    ret = (c == '-') ? 0 : (c - '0');
    while(c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return true;
}

int n, m;
int s[MAX_N][MAX_N], a[MAX_N];
ll dp[MAX_N][MAX_N], sum[MAX_N], w[MAX_N][MAX_N];

int main() {
    while (2 == scanf("%d%d", &n, &m)) {
        if (n == 0 && m == 0) break;
        for (int i = 0; i < n; ++i) rd(a[i]);
        for (int i = 0; i < n; ++i) sum[i] = i == 0 ? a[i] : sum[i - 1] + a[i];
        w[0][0] = 0;
        for (int i = 1; i < n; ++i) 
            w[0][i] = a[i] * sum[i - 1] + w[0][i - 1];
        for (int i = 1; i < n; ++i) 
            for (int j = i + 1; j < n; ++j) 
                w[i][j] = w[i][j - 1] + a[j] * (sum[j - 1] - sum[i - 1]);
        for (int i = 0; i < n; ++i) dp[0][i] = w[0][i], s[0][i] = 0, s[i][n] = n - 1;
        for (int i = 1; i <= m; ++i) 
            for (int j = n - 1; j >= 0; --j) {
                ll now = 0x3f3f3f3f, id = 0;
                for (int k = s[i - 1][j]; k <= s[i][j + 1]; ++k)
                    if (now > dp[i - 1][k] + w[k + 1][j]) {
                        now = dp[i - 1][k] + w[k + 1][j];
                        id = k;
                    }
                s[i][j] = id, dp[i][j] = now;
            }
        printf("%I64d\n", dp[m][n - 1]);
    }
    return 0;
}
View Code

 

学习资料

posted @ 2015-07-31 16:37  mithrilhan  阅读(169)  评论(0编辑  收藏  举报