【c++】贪心算法2

贪心算法2 ta来啦!!!

对贪心基础思想和基础问题还不理解的请回看上一次的

http://t.csdn.cn/Hk5Zg

OK,难度升级

我们先来看线段覆盖类问题

5220 摄像头1

在一条长度为𝐿的笔直的公路上安装若干个摄像头,用于监控交通状况。我们可以把这条公路看作数轴[0,𝐿]。何老板承包了这项工程,但交管部门对摄像头的安置提出了𝑛个要求,每个要求形如[𝑥,𝑦],表示在[𝑥,𝑦]这段区间至少要安置一个摄像头。 何老板想要用尽可能少的成本完成这项工程,因此,他想知道,最少需要安装多少个摄像头? 数据范围:𝑛≤10^5,0≤𝑥≤𝑦≤10^9

数据范围:𝑛≤10^5,0≤𝑥≤𝑦≤10^9

输入格式: 第一行,一个整数𝑛,表示有𝑛个要求需要满足。 接下来𝑛行,每行两个整数𝑥和𝑦,表示一个要求,即𝑥,𝑦这段区间至少要求一个摄像头。

输入格式: 一行,一个整数,表示最少所需摄像头的个数。

样例输入: 

4

3 6

2 4

0 2

4 7 

样例输出

2 

 解析:

从左到右安装摄像头,所以将𝑛个要求从左到右排序?

贪心策略:?

1. 将线段按从左到右排序    按左端点排序?按右端点排序? 待定

2. 枚举线段,如果需要新摄像头,尽量靠右    新摄像头放在这条线段的右端点。

3. 推断排序规则:

解析: 从左到右安装摄像头,所以将𝑛个要求从左到右排序?

贪心策略:

将𝑛个需求按右端点从小到大排序 依次枚举需求,如果没有被满足,就在它的右端点装一个摄像头 判断有没有被满足,只需要检查已安装的最右边一个摄像头是否在范围内

间复杂度𝑂𝑛log𝑛。

重点代码

sort(D+1,D + n + 1, cmp); //按区间右端点由小到大排序,区间i的左右界分别是D[i].Left, D[i].Right
int cnt = 1;
int Now = D[1].Right; //Now表示当前安装摄像头的位置
for(i = 2; i <= n; i++) {
    if( Now < D[i].Left ) { //i号区间没有被摄像头覆盖
          cnt++;
          Now = D[i].Right; //新安装摄像头的位置
    }
}

5221 摄像头2

NK中学里有一条长度为L的笔直道路,同学们可以把该路看作数轴,路的一段坐标为0,一段坐标为L,表示区间[0,L], 在这条路上安装有n个摄像头,每个摄像头都有一定的拍摄区间,第i个摄像头覆盖的区间为[Xi,Yi]。本着节约用电的态度,何老板想知道,最少开启几个摄像头就可以将整个这条路都置于视频监控中?请你帮他回答。 数据范围:1<=n<=100000 ; 1<=L<=1000000000; 0<=x<=y<=1000000000

解析: 最小线段覆盖问题:最少几条线段就能覆盖整个指定区间

 已知:x1 < x2 < x3 < x4 < x5 < x6

考虑1:有如下四条线段,优先选哪一条?

[x1,x2]    [x1,x4]    [x2,x3]    [x2,x4]

显然,选[x1,x4],即左端点越小越好,若相同,右端点越大越好。

 考虑2:若已选[x1,x4],如下三条线段,优先选哪一条?

[x2,x5]    [x3,x5]    [x3,x6]显然,选[x3,x6]

即选左端点在区间[x1,x4]中且右端点尽可能大的线段

 

 贪心算法:

1.将线段按左端点由小到大排序,若左端点相同,按右端点由大到小排序(这是根据考虑1的结论); 2.从左往右讨论每条线段,优先选择右端点大的线段:

记录目前已选线段中,往右最远能覆盖到的位置NowFar

讨论所有左端点<=NowFar且未被讨论过的线段,记录其中右端点的最大值MaxRight(这是根据考虑2的结论)

若MaxRight>NowFar,则将NowFar=MaxRight; 否则无解。

重点代码

int solve() {// 数 组 D[] 记 录 每 条 线 段 , 已 排 序 ,D[i].L 和 D[i].R 记 录 i 号 线 段 的 左 右 端 点 。
	if(D[1].L>0)    return -1; //本题覆盖的起点从0开始
	int cnt=1;
	int NowFar = D[1].R; //NowFar记录当前覆盖到的位置,即[0,NowFar]都被覆盖了。
	int MaxRight = D[1].R;
	if ( NowFar>=Len )    return cnt;
	int i=2;
	while(true){ //下面for循环找出所有左端点<=Now且未被讨论过的线段中,右端点的最大值
  		for(;i<=n&&D[i].L<=NowFar; i++) 
        		MaxRight=max(MaxRight,D[i].R);        
   		if(MaxRight<=NowFar)    return -1;      //说明区间断开了,无法连续覆盖 
   
   		cnt++;
   		NowFar=MaxRight;
   		if(NowFar>=Len)      return cnt;
	}
	return -1;
}//每条线段只有一次被讨论的机会,时间复杂度O(n)

再看一个调度问题

 样例输入

3 2

1 2 3

样例输出

1

大概能看出策略:

当有空闲的机器的时候,优先加工所需时间长的工件; 当没有空闲机机器的时候,等待加工完毕就有空闲机器了 

 贪心策略:

当有空闲的机器的时候,优先加工所需时间长的工件; 每次的工件都选择当前最快的生产线(尽快结束前面加工任务的生产线)

重点代码

cin>>n>>r;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	sort(a+1,a+n+1);
	for(int i=n;i>=1;--i){
		a1[1]+=a[i];
		sort(a1+1,a1+1+r);
	}
	cout<<a1[r];

贪心就讲到这里

(记得多做题) 

完结撒花!!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hear the Wind Sing.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值