题意是:输入几个样例,每个样例第一行输入从0开始需要覆盖的长度M,即[0,M]。之后输入覆盖的线段,求需要的线段条数最小值。
Input
Output
思路:贪心算法,具体见代码及注释。
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
using namespace std;
#define MAXN 100001
/*将输入数据进行处理,右边小于0的和左边大于M的删除
然后以Li尽量小,Ri尽量大的顺序进行排序,每次寻找到一个,
假如Li大于0,就以最小的Li当作结束继续寻找
(同理假如已经找到的Ri小于M,则继续以M为结束继续寻找)
即贪心算法*/
struct Segs{
int l;
int r;
};
bool cmp(Segs a,Segs b){//sort函数的_Compare部分
return a.l < b.l;
}
class MinCover{
private:
int M;//需要覆盖的长度
Segs segs[MAXN],result[MAXN];//有效输入线段数组和结果数组
int segNum;//有效线段数目
public:
void init();
void readData();
void process();
};
void MinCover::init(){
memset(segs,-1,sizeof(segs));
memset(result,-1,sizeof(result));
}
void MinCover::readData(){
cin>>M;
int i = 0;
while(cin>>segs[i].l>>segs[i].r){
if(segs[i].l==0 && segs[i].r==0)break;
if(segs[i].l > M||segs[i].r < 0)continue;//假如左边大于M,右边小于0,不储存
i++;
}
segNum = i;
}
void MinCover::process(){
sort(segs,segs + segNum,cmp);
int left = 0,right,isFind;
int loop = 0,index;
while(left < M){
isFind = 0;
right = left;//右端起始值和左边一致,随左端更新而更新
for(int j = 0;j < segNum;j++){//贪心,
if((segs[j].l <= left) && (segs[j].r > right)){//寻找到的值应小于左端,大于“右端”
index = j;
isFind = 1;
right = segs[j].r;
}
}
if(isFind==1){
result[loop++] = segs[index];
left = segs[index].r;//将找到的最大右边作为即将继续寻找的起点。
}
else break;
}
if(isFind==1){
cout<<loop<<endl;
for(int k = 0;k < loop;k++){
cout<<result[k].l<<" "<<result[k].r<<endl;
}
}
else
cout<<0<<endl;
}
int main()
{
//freopen("D:\\acm.txt","r",stdin);
int cases;
MinCover mincover;
mincover.init();
cin>>cases;
while(cases--){
mincover.readData();
mincover.process();
if(cases>0)cout<<endl;
}
return 0;
}
测试数据:请直接选中复制,点击复制按钮会导致数据缺少。
来源:http://www.algorithmist.com/index.php?title=UVa_10020
Input
7 1 -1 0 -5 -3 2 5 0 0 1 -1 0 0 1 0 0 10 -2 5 -1 6 -1 3 0 4 1 5 2 6 3 7 7 8 8 10 8 9 0 0 10 -2 5 -1 6 -1 3 0 4 1 5 2 6 3 7 8 10 8 9 0 0 10 2 5 5 3 2 3 2 5 0 0 10 0 10 0 10 0 0 6 0 2 2 4 4 6 6 8 0 0
Output
0 1 0 1 4 -1 6 3 7 7 8 8 10 0 0 1 0 10 3 0 2 2 4 4 6