用i表示x轴上坐标为[i-1,i]的区间(区间长度为1),并给出n个不同的整数来表示n个这样的区间。现在要求画出几条线段覆盖住所有的区间,条件是:每条线段可任意长,但要求所画线段长度之和最小,并且线段的数目不超过m。
输入格式:
第一行输入表示区间个数n和最大线段数m。 第2行输入n个点的坐标。
输出格式:
输出能覆盖所有区间的线段最小长度和。
输入样例:
5 3
1 3 8 5 11
输出样例:
7
用a[ ]储存线段的位置,排序之后用dis[ ]储存相邻两条线段之间的距离,将距离从小到大排序。将二分答案的左端点初始化成n(只覆盖所有线段,每条线段长度为1,覆盖之后线段条数是n)右端点控制成a[n-1]-a[0]+1(简单粗暴地一笔从头涂到尾,覆盖之后只有一条线段),然后重点是check函数怎么写。
bool check(int t)
{
int cnt=0;
t-=n;
for(int i=1;i<n;i++)
{
t-=dis[i];
if(t<0)
break;
cnt++;
}
if(n-cnt<=m)
return true;
return false;
}
先把所有的a[ ]里的线段涂上,然后我们看在剩下的t里连接几笔,最后能不能剩下小于m的线段条数,可以的话返回true,否则返回false。从两边逐步向答案逼近,直到跳出循环为止算出来的就是最终答案。
#include<bits/stdc++.h>
using namespace std;
int a[100000],dis[100000];
int n,m,i;
bool check(int t)
{
int temp=t;
int cnt=0;
t-=n;
for(int i=1;i<n;i++)
{
t-=dis[i];
if(t<0)
{
break;
}
cnt++;
}
if(n-cnt<=m)
{
//cout<<temp<<" 1"<<endl;
return true;
}
else
{
//cout<<temp<<" 0"<<endl;
return false;
}
}
int main()
{
cin>>n>>m;
for(i=0;i<n;i++)
cin>>a[i];
sort(a,a+n);
for(i=1;i<n;i++)
dis[i]=a[i]-a[i-1]-1;
sort(dis+1,dis+n);
//for(i=1;i<n;i++)
//cout<<dis[i]<<' ';
int l,r,ans;
l=n;
r=a[n-1]-a[0]+1;
while(l<=r)
{
//cout<<"left"<<l<<' '<<"right"<<r<<endl;
int mid=(l+r)/2;
if(check(mid))
{
ans=mid;
r=mid-1;
}
else
l=mid+1;
}
cout<<ans;
return 0;
}