贪心法——区间覆盖问题
2016-06-03 22:18
856 查看
贪心法——区间覆盖问题
区间覆盖问题。数轴上有n个闭区间[ai,bi],选择尽量少的区间覆盖一条指定线段[s,t]。先进行预处理,将不包含[s,t]的区间都去掉,然后再按左区间从小到大排序。如果最小区间的左区间大于s的话,则无解。选取包含s的右区间最大的区间,该区间的右区间仍然小于下一个区间的左区间,则无解。按照这样的方法一直选择到最后一个区间,如果最后一个区间的右区间小于t,则无解。否则输出所有区间。
区间覆盖问题实现代码
// 区间数据结构 struct Region { // 左区间 int left; // 右区间 int right; operator < (const Region &r) { return left < r.left; } }; // 贪心法 // 区间覆盖问题 void region(Region *r, int n, Region target) { // 预处理,将和target有交集的区间提取出来 int num = 0; Region re ; for(int i = 0; i < n; i++) { // 和目标线段无交集 if(r[i].left > target.right || r[i].right < target.left) { continue; } re[num++] = r[i]; } // 区间是否覆盖完全 int isCover = 1; // 处理后无区间 if(!num) { isCover = 0; } // 按左区间大小从小到大排序 sort(re, re + num); // 当前最大区间 Region curMax = re[0]; // 记录覆盖区间 vector<Region> coverR; // 处理覆盖最左边的问题 if(curMax.left > target.left) { isCover = 0; } // 处理覆盖中间问题 for(int i = 1; i < num; i++) { // 下一个区间和当前最大区间无交集 if(re[i].left > curMax.right) { isCover = 0; break ; } // 覆盖右区间比当前最大区间大,且还能覆盖到目标区间左区间 if(re[i].right > curMax.right && re[i].left <= target.left) { curMax.left = re[i].left; curMax.right = re[i].right; } else if(re[i].left > target.left) { coverR.push_back(curMax); // 目标区间左区间设置为最大区间右区间 target.left = curMax.right; // 该区间覆盖右区间比最大右区间大 if(re[i].right > curMax.right) { curMax.left = re[i].left; curMax.right = re[i].right; } } } // 处理覆盖最右边的问题 if(curMax.right < target.right) { isCover = 0; } else { coverR.push_back(curMax); } // 输出 if(isCover) { for(int i = 0; i < coverR.size(); i++) { cout << "区间:(" << coverR[i].left << "," << coverR[i].right << ")" << endl; } cout << "区间总数为:" << coverR.size() << endl << endl; } else { cout << "无解。" << endl << endl; } }
测试主程序
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
// 区间数据结构 struct Region { // 左区间 int left; // 右区间 int right; operator < (const Region &r) { return left < r.left; } }; // 贪心法 // 区间覆盖问题 void region(Region *r, int n, Region target) { // 预处理,将和target有交集的区间提取出来 int num = 0; Region re ; for(int i = 0; i < n; i++) { // 和目标线段无交集 if(r[i].left > target.right || r[i].right < target.left) { continue; } re[num++] = r[i]; } // 区间是否覆盖完全 int isCover = 1; // 处理后无区间 if(!num) { isCover = 0; } // 按左区间大小从小到大排序 sort(re, re + num); // 当前最大区间 Region curMax = re[0]; // 记录覆盖区间 vector<Region> coverR; // 处理覆盖最左边的问题 if(curMax.left > target.left) { isCover = 0; } // 处理覆盖中间问题 for(int i = 1; i < num; i++) { // 下一个区间和当前最大区间无交集 if(re[i].left > curMax.right) { isCover = 0; break ; } // 覆盖右区间比当前最大区间大,且还能覆盖到目标区间左区间 if(re[i].right > curMax.right && re[i].left <= target.left) { curMax.left = re[i].left; curMax.right = re[i].right; } else if(re[i].left > target.left) { coverR.push_back(curMax); // 目标区间左区间设置为最大区间右区间 target.left = curMax.right; // 该区间覆盖右区间比最大右区间大 if(re[i].right > curMax.right) { curMax.left = re[i].left; curMax.right = re[i].right; } } } // 处理覆盖最右边的问题 if(curMax.right < target.right) { isCover = 0; } else { coverR.push_back(curMax); } // 输出 if(isCover) { for(int i = 0; i < coverR.size(); i++) { cout << "区间:(" << coverR[i].left << "," << coverR[i].right << ")" << endl; } cout << "区间总数为:" << coverR.size() << endl << endl; } else { cout << "无解。" << endl << endl; } }
int main() {
while(true) {
// n个开区间
int n;
cout << "请输入闭区间的数量(0退出):";
cin >> n;
if(!n) {
break;
}
// 需要覆盖的线段区间
Region target;
cout << "需要覆盖的线段区间为:";
cin >> target.left >> target.right;
Region r
;
for(int i = 0; i < n; i++) {
cout << "第" << i + 1 << "个闭区间(x,y)为:";
cin >> r[i].left;
cin >> r[i].right;
}
cout << "最少区间能覆盖线段区间[" << target.left << "," << target.right <<"]组合和总数为:" << endl;
region(r, n, target);
}
return 0;
}
输出数据
请输入闭区间的数量(0退出):5 需要覆盖的线段区间为:5 10 第1个闭区间(x,y)为:1 3 第2个闭区间(x,y)为:3 6 第3个闭区间(x,y)为:5 7 第4个闭区间(x,y)为:7 9 第5个闭区间(x,y)为:8 11 最少区间能覆盖线段区间[5,10]组合和总数为: 区间:(5,7) 区间:(7,9) 区间:(8,11) 区间总数为:3 请输入闭区间的数量(0退出):3 需要覆盖的线段区间为:5 9 第1个闭区间(x,y)为:1 3 第2个闭区间(x,y)为:1 4 第3个闭区间(x,y)为:2 3 最少区间能覆盖线段区间[5,9]组合和总数为: 无解。 请输入闭区间的数量(0退出):3 需要覆盖的线段区间为:5 9 第1个闭区间(x,y)为:10 11 第2个闭区间(x,y)为:12 13 第3个闭区间(x,y)为:14 15 最少区间能覆盖线段区间[5,9]组合和总数为: 无解。 请输入闭区间的数量(0退出):5 需要覆盖的线段区间为:5 9 第1个闭区间(x,y)为:6 7 第2个闭区间(x,y)为:7 8 第3个闭区间(x,y)为:8 9 第4个闭区间(x,y)为:9 10 第5个闭区间(x,y)为:10 11 最少区间能覆盖线段区间[5,9]组合和总数为: 无解。 请输入闭区间的数量(0退出):5 需要覆盖的线段区间为:5 9 第1个闭区间(x,y)为:1 5 第2个闭区间(x,y)为:5 6 第3个闭区间(x,y)为:5 7 第4个闭区间(x,y)为:8 9 第5个闭区间(x,y)为:9 10 最少区间能覆盖线段区间[5,9]组合和总数为: 无解。 请输入闭区间的数量(0退出):5 需要覆盖的线段区间为:5 9 第1个闭区间(x,y)为:1 5 第2个闭区间(x,y)为:5 6 第3个闭区间(x,y)为:5 7 第4个闭区间(x,y)为:5 8 第5个闭区间(x,y)为:6 7 最少区间能覆盖线段区间[5,9]组合和总数为: 无解。 请输入闭区间的数量(0退出):0 Process returned 0 (0x0) execution time : 172.044 s Press any key to continue.
相关文章推荐
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- 经典排序算法之冒泡排序(Bubble sort)代码
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法
- 基于C++实现的各种内部排序算法汇总
- C++线性时间的排序算法分析
- C++实现汉诺塔算法经典实例