HDU 5699 货物运输

来源:互联网 发布:300英雄辅助软件 编辑:程序博客网 时间:2024/05/01 11:14

点击打开链接


题解:(备注:其实有博客这个题目的题解写的很好,我随便写的有点乱,我想记录的是我wa的原因,还有为什么思路是这个?这些想法都在代码的后面)

因为题目是在一个区间里面找到一个数(0—n),而且其实只要时间t越大,t是可以满足所有的运输方案都能在t时间内完成。

所以我们要找的是最大值中的最小值~ 所以可以用二分做,而且有点像二分里的二分法求下界的感觉。

二分下界是按照紫书的算法模型理解的。~

问题在于if的条件判断。

对于每一个li和ri,(令r >= l)

如果   ri - li ≤ mid ,他可以不用传送器~

如果 大于 ,那么设传送器为x , y ( x >= y)

则 | ri - x | - | ri - y | <= mid.

把它拆成四个不等式即可以知道 x+y 与 y-x 的范围

     l+r-mid<= x+y <=l+r+mid;

     r-l-mid<=y-x<=r-l+mid;

那么if的条件成立就是  对于所有的(划重点)需要传送器的点而言,x+y和y-x都可以算出解来。

那么x+y的最大值l+r-mid就是所有需要传送器的点的这个值的最小值。

即 max1=min(max1,l+r+mid);

同理 x+y的最小值 min1=max(min1 , l+r-mid);  y-x的最小值min2=max(min2 , r-l-mid) ; max2=min(max2, r-l+mid);

那么为了有解可得,则 x+y的最小值的最大值(max1)要 小于等于 最大值的最小值(min1);

x-y的最小值的最大值(max2) 要小于等于 最大值的最小值(min2);


AC代码:

#include <iostream>#include <cmath>#include <algorithm>#include <stdio.h>#include <stack>#define pie ((long double)acos(-1))#define max(x1,x2) ((x1)>(x2)?(x1):(x2))#define min(x1,x2) ((x1)<(x2)?(x1):(x2))using namespace std;const int maxn=10e6+10;int n,m;int L,R,mid;int l[maxn],r[maxn];bool check(int mid){    int maxx1=0x7fffffff;    int maxx2=0x7fffffff;    int minn1=-0x7fffffff;    int minn2=-0x7fffffff;    for(int i=0;i<m;i++)    {        if(r[i]-l[i]>mid){             maxx1=min(l[i]+r[i]+mid,maxx1);             minn1=max(l[i]+r[i]-mid,minn1);             maxx2=min(r[i]-l[i]+mid,maxx2);             minn2=max(r[i]-l[i]-mid,minn2);        }    }    int flag=0;    if(maxx1>=minn1 && maxx2>=minn2)    {        flag=1;        if(maxx1==minn1&& maxx2==minn2 )           {               if((maxx1+maxx2)%2==1)                  flag=0;           }    }    if(flag==0) return false;    else return true;}int main(){    while(cin>>n>>m)    {        for(int i=0;i<m;i++)      {          scanf("%d%d",&l[i],&r[i]);          if(l[i]>r[i])          {              int temp=l[i];              l[i]=r[i];              r[i]=temp;          }      }      //二分      L=0;      R=n;      mid=0;      while(L<R)      {          mid=L+(R-L)/2;          if(check(mid)) R=mid;          else L=mid+1;      }      cout<<L<<endl;    }    return 0;}

上面写的思路和AC代码有一点点不一样,思路是能过的.要是看了别的博客肯定知道为啥弄个flag了。


我想补充的是:

1.我们为什么要通过x+y ,y-x的范围来判断二分? 实际上其实我们是想知道 当mid等于当前值的时候,我们能不能找到(至少)一对x,y来构建传送器。

当然我们可以求出x,y但是其实没必要算出来,而且很麻烦QAQ

2.强调是“所有的(划重点)需要传送器的点而言,x+y和y-x都可以算出解来”,我一开始先通过四个不等式直接算出x和y的不等式(而不是x+y和x-y),

结果是错的就是因为考虑不对。

3.

if(r[i]-l[i]>mid)
这句我本来觉得> 和>=是差不多的,因为如果刚好可以使用传送器何乐而不为呢,但是后来wa了。。。。

我举了例子想了想是因为,当r-l=mid时,你拿l和r去算max和min,可能会使x,y的范围变苛刻,这样可能真正需要传送器的点结果用不了传送器了。

所以不能写等号~

4.题目是“多组数据”。。。。。我没仔细看QAQ 题目写得好精练???QAQ