POJ 1160 Post Office
题意:给你
n
n
n个点,在这
n
n
n个点中选择
m
m
m个点建立基站,定义节点
i
i
i到基站
j
j
j处的花费
a
b
s
(
j
−
i
)
abs(j - i)
abs(j−i),让你求解最小花费.
分析:
我的暴力:预处理区间
(
L
,
R
)
(L,R)
(L,R)建立一个基站的最小花费,
d
p
[
i
]
[
j
]
:
表
示
前
i
个
点
建
立
j
个
基
站
的
最
小
花
费
dp[i][j]:表示前i个点建立j个基站的最小花费
dp[i][j]:表示前i个点建立j个基站的最小花费,然后常规区间DP操作:枚举基站
j
j
j、右端点
i
i
i(左端点默认为1)、插值
k
k
k,
O
(
n
2
∗
l
g
(
n
)
+
n
2
∗
m
)
O(n^2*lg(n) + n^2 * m)
O(n2∗lg(n)+n2∗m)。
四边形不等式优化:注意初始化。。。
直接套着结构去用就行,不过这里的
s
[
i
]
[
j
]
s[i][j]
s[i][j]表示的不是基站位置,而是右端点
i
i
i.
CODE-1:
#pragma GCC optimize ("O3")
#pragma GCC optimize ("O2")
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int MAXN = 1000 + 10;
int dp[MAXN][35], s[MAXN][35], a[MAXN];
pii c[MAXN][MAXN];
pii so(int L, int R) {
pii ans; ans.first = 0, ans.second = 0;
for(int i = L; i <= R; ++i) ans.first += (a[i] - a[L]);
for(int i = L + 1; i <= R; ++i) {
int cnt = (a[i] - a[i - 1]) * (i + i - L - R - 1);
if(cnt > 0) continue;
ans.first = ans.first + cnt;
ans.second = i;
}
return ans;
}
int main() {
int n, m; memset(dp, INF, sizeof(dp));
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
for(int i = 1; i <= n; ++i) {
pii ans = so(1, i);
dp[i][1] = ans.first;
s[i][1] = ans.second;
//printf("# %d %d\n", dp[i][1], s[i][1]);
}
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= i; ++j) {
c[j][i] = so(j, i);
//printf("# %d\n", c[i][j].first);
}
}
for(int j = 2; j <= m; ++j) {
for(int i = n; i >= 1; --i) {
for(int k = 1; k <= i; ++k) {
pii ans = c[k][i];
if(dp[k - 1][j - 1] + ans.first <= dp[i][j]) {
dp[i][j] = dp[k - 1][j - 1] + ans.first;
s[i][j] = ans.second;
}
}
}
}
printf("%d\n", dp[n][m]);
return 0;
}
CODE-2:
#pragma GCC optimize ("O3")
#pragma GCC optimize ("O2")
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int MAXN = 1000 + 10;
int dp[MAXN][35], s[MAXN][35], a[MAXN];
int c[MAXN][MAXN];
int so(int L, int R) {
int ans = 0;
for(int i = L; i <= R; ++i) ans += (a[i] - a[L]);
for(int i = L + 1; i <= R; ++i) {
int cnt = (a[i] - a[i - 1]) * (i + i - L - R - 1);
if(cnt > 0) continue;
ans = ans + cnt;
}
return ans;
}
int main() {
int n, m; memset(dp, INF, sizeof(dp));
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
for(int i = 1; i <= n; ++i) {
dp[i][1] = so(1, i);
s[i][1] = 1;
for(int j = 1; j <= i; ++j) {
c[j][i] = so(j, i);
}
}
for(int j = 2; j <= m; ++j) {
s[n + 1][j] = n; //别忘记初始化
for(int i = n; i >= 1; --i) {
for(int k = s[i][j - 1]; k <= s[i + 1][j]; ++k) {
if(dp[k - 1][j - 1] + c[k][i] <= dp[i][j]) {
dp[i][j] = dp[k - 1][j - 1] + c[k][i];
s[i][j] = k;
}
}
}
}
printf("%d\n", dp[n][m]);
return 0;
}