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

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

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

思路:

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


POJ 3171 Cleaning Shifts 线段树+动态规划_第1张图片
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;
}



你可能感兴趣的:(POJ 3171 Cleaning Shifts 线段树+动态规划)