题意:输入n,m,然后两个n*m的矩阵,第一个代表在这个位置建塔的成本,第二个代表在相应位置建塔能照的距离,要求每行建一个,并且相邻两行的两个塔要满足照的距离之和大于等于列号差。求最小成本。
分析:每一行中建立一个塔后会在这行照亮一段距离,如果下一行中的一个点能照到这段区间,表示这两个是可以同时建的。也就是下一行中的一个点要在这一行中的对应区间找一个成本最小值,动态规划的状态传递比较好写,只是一行最多有5000个点,照最小值要用线段树优化。
这个题在场上看出来是要用线段树了,本来线段树就比较弱,又很久没有写过了,结果一个半小时都没有写出来,最终补题的时候也是错了好多遍才出,一直TLE,结果最后是因为数组开小了……无语。。。不过最终能手写出来还是挺有成就感的。
#include <string.h>
#include <stdio.h>
int INF = 0x3f3f3f3f;
struct node {
int b, e, d, same;
}id[2][22000];
int f[105][5005];
int t[105][5005];
void init(int f, int u, int b, int e) {
id[f][u].b = b;
id[f][u].e = e;
id[f][u].d = INF;
id[f][u].same = INF;
if(b != e) {
int m = (b + e) >> 1;
init(f, u << 1, b, m);
init(f, (u << 1) + 1, m + 1, e);
}
}
void update(int f, int u, int b, int e, int d) {
if(d < id[f][u].d)
id[f][u].d = d;
if(id[f][u].b == b && e == id[f][u].e) {
if(id[f][u].same > d)
id[f][u].same = d;
return;
}
int m = (id[f][u].b + id[f][u].e) >> 1;
int lc = (u << 1), rc = (u << 1) + 1;
if(e <= m) {
update(f, lc, b, e, d);
}
else if(b > m)
update(f, rc, b, e, d);
else{
update(f, lc, b, m, d);
update(f, rc, m + 1, e, d);
}
}
int query(int f, int u, int b, int e) {
if((id[f][u].b == b && id[f][u].e == e)) {
return id[f][u].d;
}
if(id[f][u].same <= id[f][u].d)
return id[f][u].same;
int m = (id[f][u].b + id[f][u].e) >> 1, x, y;
int lc = u << 1, rc = (u << 1) + 1;
if(e <= m) {
x = query(f, lc, b, e);
return id[f][u].same < x ? id[f][u].same : x;
}
else if(b > m) {
x = query(f, rc, b, e);
return id[f][u].same < x ? id[f][u].same : x;
}
else{
x = query(f, lc, b, m);
y = query(f, rc, m + 1, e);
x = y < x ? y : x;
return id[f][u].same < x ? id[f][u].same : x;
}
}
int main() {
int n, m, i, j, mn, a, b;
while(~scanf("%d%d", &n, &m) && (n || m)) {
for(i = 0; i < n; i++){
for(j = 0; j < m; j++){
scanf("%d", &t[i][j]);
}
}
for(i = 0; i < n; i++){
for(j = 0; j < m; j++){
scanf("%d", &f[i][j]);
}
}
init(0, 1, 0, m - 1);
for(j = 0; j < m; j++) {
a = j - f[0][j];
b = j + f[0][j];
if(a < 0)
a = 0;
if(b > m - 1)
b = m - 1;
update(0, 1, a, b, t[0][j]);
}
for(i = 1; i < n; i++) {
init(i & 1, 1, 0, m - 1);
for(j = 0; j < m; j++){
a = j - f[i][j];
b = j + f[i][j];
if(a < 0)
a = 0;
if(b > m - 1)
b = m - 1;
mn = query(((~i) & 1), 1, a, b);
update((i & 1), 1, a, b, t[i][j] + mn);
}
}
printf("%d\n", query((~n) & 1, 1, 0, m - 1));
}
return 0;
}