UVa 10020 - Minimal coverage
题意是:输入几个样例,每个样例第一行输入从0开始需要覆盖的长度M,即[0,M]。之后输入覆盖的线段,求需要的线段条数最小值。
思路:贪心算法,具体见代码及注释。
#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
Donghua University