糯米

TI DaVinci, gstreamer, ffmpeg
随笔 - 167, 文章 - 0, 评论 - 47, 引用 - 0
数据加载中……

POJ 3171 Cleaning Shifts 线段树+动态规划

这题看似挺有实际用途的,呵呵。
大意就是用最小的花费覆盖一段区间。

思路:

动态规划,就是说,将线段的左端点从左到右排序。依次处理:



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)->- ((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(
11, M, E, end, end, &in[i].s);
            
continue;
        }

        val 
= INT_MAX;
        tree_op(
01, M, E, start, end, &val);
        
if (val == INT_MAX)
            
continue;
        val 
+= in[i].s;
        tree_op(
11, M, E, end, end, &val);
    }


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

    
return 0;
}



posted on 2010-03-30 21:52 糯米 阅读(763) 评论(0)  编辑 收藏 引用 所属分类: POJ


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理