您的位置:首页 > 其它

贪心法——区间覆盖问题

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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息