|
这题看似挺有实际用途的,呵呵。 大意就是用最小的花费覆盖一段区间。
思路:
动态规划,就是说,将线段的左端点从左到右排序。依次处理:
 1. 假设已经知道,所有的短线拼接起来之后,能组成哪几条长线(M为左端点)。 2. 当我们放入一条短线的时候,它能够和旧长线继续拼接。这时候,我们需要选取花费最小的那条。 3. 拼接之后,生成一条新的长线。 在(2)中,“选取花费最小的那条”可以用线段树来实现。也就是求区间内的最小值,RMQ问题,由于只插入不删除,线段树是可以维护的。 就这样一直处理,最终答案就是花费最小的以E为右端点的长线。 代码 94MS:
#include <stdio.h>
#include <stdlib.h>

#ifndef INT_MAX
#define INT_MAX 0x7fffffff
#endif

 struct tree_node {
int cnt, min;
};
 struct seg_node {
int a, b, s;
};
int N, M, E;
struct tree_node tree[86432 * 4];
struct seg_node in[10032];

int cmp(const void *a, const void *b)
  {
return ((struct seg_node *)a)->a - ((struct seg_node *)b)->a;
}

__inline int max(int a, int b)
  {
return a > b ? a : b;
}

__inline int min(int a, int b)
  {
return a < b ? a : b;
}

void tree_op(const int ins,
int idx,
int left, int right,
int start, int end,
int *val
)
  {
int mid;

 if (ins) {
if (!tree[idx].cnt || *val < tree[idx].min)
tree[idx].min = *val;
tree[idx].cnt++;
}

 if (left == start && right == end) {
if (!ins && tree[idx].cnt && tree[idx].min < *val)
*val = tree[idx].min;
return ;
}

mid = (left + right) / 2;
if (end <= mid)
tree_op(ins, idx*2, left, mid, start, end, val);
else if (start > mid)
tree_op(ins, idx*2 + 1, mid + 1, right, start, end, val);
 else {
tree_op(ins, idx*2, left, mid, start, mid, val);
tree_op(ins, idx*2 + 1, mid + 1, right, mid + 1, end, val);
}
}

int main()
  {
int i, val, start, end;

freopen("e:\\test\\in.txt", "r", stdin);

scanf("%d%d%d", &N, &M, &E);
for (i = 0; i < N; i++)
scanf("%d%d%d", &in[i].a, &in[i].b, &in[i].s);
qsort(in, N, sizeof(in[0]), cmp);

 for (i = 0; i < N; i++) {
if (in[i].b < M)
continue;
if (in[i].a > E)
break;
start = max(M, in[i].a - 1);
end = min(E, in[i].b);
 if (in[i].a == M) {
tree_op(1, 1, M, E, end, end, &in[i].s);
continue;
}
val = INT_MAX;
tree_op(0, 1, M, E, start, end, &val);
if (val == INT_MAX)
continue;
val += in[i].s;
tree_op(1, 1, M, E, end, end, &val);
}

val = INT_MAX;
tree_op(0, 1, M, E, E, E, &val);
printf("%d\n", val == INT_MAX ? -1 : val);

return 0;
}

|