【四边形】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; }