p1338区间覆盖问题(贪心之子问题)
子问题系列的贪心是一个很重要的贪心系列,可以用递归求解,虽然暂时不觉得会比普通循环好到哪里去
【问题描述】
任务1:区间覆盖问题 数轴上有n闭区间[ai,bi],选择尽量少的区间覆盖一条指定线段[s,t]。
任务2:覆盖区间问题
数轴上有n闭区间[ai,bi],选择尽量少的闭区间[cj,dj]覆盖所有的闭区间[ai,bi],且[cj,dj]所包含的点不能有n个闭区间[ai,bi]之外的点。
这次贪心建立在左端点从左到右排序的基础上
问题一
先解决第一个问题,因为这是子问题系列的贪心:取一条右端点最右并且满足条件的线段,然后解决一个子问题,因此尝试递归(不一定最好)
void f(int i,int s,int t,int ans)//求s到t的距离,选择第了ns个,从第i个开始考虑
状态怎么好写就怎么定义,不要太拘泥
{
if(s>=t&&ans!=0)//有可能s=t
{
cout<<ans<<endl;
return;
}
if(i==n+1)//排除无法覆盖情况1
{
cout<<-1<<endl;
return;
}
if(p[i].a>s)//中间断开的情况(主要)
{
cout<<-1<<endl;
return;
}
int sub=i,j;
for(j=i+1;j<=n;j++)
{
if(p[j].a<=s)
if(p[j].b>p[sub].b)
sub=j;
else break;
}
f(j,p[sub].b,t,ans+1);
}
这一段主要的问题就是判断无解比较考技术,不容易考虑到,会大家都会,但是通过率只有百分之二十
问题二
vector<data>v;//因为要先输出答案,因此只好想个办法存储
int a=p[1].a,b=p[1].b;
for(int i=1;i<=n;i++)
{
if(p[i].a<=b)
{
b=max(b,p[i].b);//这里可以选取最好的右端
}
else
{
v.push_back((data){a,b});
a=p[i].a;
b=p[i].b;
}
}
v.push_back((data){a,b});//因为最后一段无法加入,要手工,用哨兵就有点扯了
cout<<v.size()<<endl;
for(int i=0;i<v.size();i++)
{
printf("%d %d\n",v[i].a,v[i].b);
}
总结:这道题只是一个细节题,同时也有些新的手法值得积累,这个问题的类型倒是贪心中一个比较冷门的却有些难度的,顺便试试新开通的博客。。。