poj 2376 Cleaning Shifts( 贪心 )

来源:互联网 发布:网络电视怎么设置连接 编辑:程序博客网 时间:2024/04/26 04:22
 

题意:给出区间[ 1,T ]和N个小区间,要求用尽可能少的小区间覆盖区间[ 1,T ],输出最少的小区间数量;若不能覆盖,输出-1。

思路:贪心。

具体:令begin为当前未被覆盖的区间起点。

            贪心策略:选取包含点begin的区间中右端点最大的那个;若不存在包含begin的区间,输出-1。

证明:因为begin为未被覆盖的区间起点,所以begin一定要被小区间覆盖,将最优解中覆盖begin的小区间命名为区间X。

            以下使用剪贴技术证明。

            若存在包含begin的小区间Y( Y != X )使最终所需的小区间数少于原最优解,那么Y一定包含了X之后的某些小区间,

            即Y的右端点大于X的右端点,与贪心策略矛盾,得证。

#include <iostream>#include <algorithm>using namespace std;const int Max = 25000;// 对象int N, T;struct Interval {int b, e;}I[Max];// 函数bool greater( const Interval & i1, const Interval & i2 ){return i1.b < i2.b;}int Greedy(){int num = 0; // 最少区间数 intright = 0; // 已覆盖区间右端点int top = 0; // 集合首while( right < T ) {// 选出包含begin的区间中右端点最大的那个int begin = right + 1; // 待覆盖的起点for( int i = top; i < N; ++ i ) {if( I[i].b <= begin && I[i].e >= begin )right = I[i].e > right ? I[i].e : right;else if( I[i].b > begin ) {top = i;break;}}// 没有包含begin的区间if( begin > right ) break;else ++ num;}if( right == T ) return num;else return -1;}int main(){scanf( "%d%d", & N, & T );for( int i = 0; i < N; ++ i )scanf( "%d%d", & I[i].b, & I[i].e );sort( I, I + N, greater );printf( "%d\n", Greedy() );return 0;}