这一题可能贪心的策略有不少,好比以左端从小到大排序,按顺序选取知足条件的区间。或者以右端从小到大排序。node
以左端从小到大排序能够找到反例说明可能形成有短区间浪费没用到的状况。函数
而以右端点为何就不会呢?(这里给一个个人解释,但只是直观解释,没有严格的数学证实)spa
可能会形成短区间的浪费,而以右端点排序就会首先考虑段区间,因此综合考虑以右端点排序的方式更优。3d
这样右边剩余的空间最大,能够有更多的区间提供选择。code
(关于用右端点排序最优的数学证实我尚未想出来,若是哪位大佬知道但愿能够指导我一下)blog
对于区间是否选择以及cur的更新:排序
假设当前区间能够移动的最大距离为mid, 那么某个区间能够移动的范围为 [ l - mid, r + mid ],知足这个条件的区间可使用,与cur有以下四种关系:ci
综合以后 ①②为一种状况,③④为一种状况。数学
题目要求最小,那么 x==y==z/2,因此处理时只须要将每一个区间都乘以2,最后判断结果是否能被2整除。it
#include<cstdio> #include<vector> #include<algorithm> using namespace std; //输入 int n; struct node//区间 { int l; int r; node(int l1,int r1){ l = l1 ; r = r1;}//构造函数 }; vector<node> v; bool cmp(node n1, node n2) { if( n1.r==n2.r ) return n1.l<n2.l;//若是右端点相等,选择更接近cur的 return n1.r<n2.r;//以右端点从小到大排序 } bool C(int mid)//判断mid是否知足条件 { int cur = 0; vector<node> v_(v); while( true ) { bool flat = false;//有没有知足条件的区间 for(int i=0; i<v_.size(); i++) { int l = v_[i].l, r = v_[i].r; if( l-mid<=cur&&cur<=r+mid )//知足条件 { if( cur-l>=mid )//状况 1,2 { //cur += mid + r - cur; cur = mid+r; } else//状况 3,4 { cur += (r-l);// cur += len } v_.erase(v_.begin()+i);//去掉此区间 flat = true; break;//每次找到一个区间cur的状态都改变,原来不能移动的区间如今可能能够移动 } } if( !flat || cur>=20000 ) break;//若是没有知足条件的区间||已经覆盖了全部区间 } return cur>=20000; } void solve() { sort(v.begin(),v.end(),cmp); int l = 0, r = 20000; while( r-l>1 )//二分法求解 { int mid = (l+r)/2; if( C(mid) ) r = mid;//知足条件,缩小移动距离 else l = mid; } if( r%2==0 ) printf("%d\n",r/2); else printf("%.1f\n",(float)r/2.0); } int main() { scanf("%d",&n); while( n-- ) { int l,r; scanf("%d%d",&l,&r); v.push_back(node(2*l,2*r));//每一个区间乘以2 } solve(); return 0; }