飞机调度(Now or later,LA 3211)

AC通道( Uva 1146 ):
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3587


飞机调度


Description

n 架飞机需要着陆。
每架飞机都可以选择“早着陆”和“晚着陆”两种方式之一,且必须选择一种。
i 架飞机的早着陆时间为 Ei ,晚着陆时间为 Li ,不得在其他时间着陆。
你的任务是为这些飞机安排着陆方式,使得相邻两个着陆时间间隔的最小值(称为安全间隔)应尽量大。


Input

输入包含若干组数据。
每组数据第一行为飞机的数目 n 2n2000 )。
以下 n 行每行两个整数,及早着陆时间和晚着陆时间。
所有时间 t 满足 0t107
输入结束标志为文件结束符( EOF )。


Output

对于每组数据,输出安全间隔的最大值。


Sample Input

10
44 156
153 182
48 109
160 201
55 186
54 207
55 165
17 58
132 160
87 197


Sample Output

10


Solution

首先,看到这个最小值最大,就毫不犹豫地想到了二分答案。
这样,我们就把问题转化为了判定性问题,即是否能使相邻两个着陆时间差不小于 P

我们可以构一张图。
图中编号为 2k+b0b11kn 的节点的值若为 1 ,表示第 k 架飞机,选择第 b+1 种着陆方式;值若为 0 ,则表示表示第 k 架飞机,不选择第 b+1 种着陆方式。
即一个节点表示一个决策。

而对于有向边 x -> y ,表示选择决策 x ,就可以推出必须选择决策 y
怎样才可以从一个决策推出另一个决策呢?
我们可以发现,若决策 x 的着陆时间与决策 y 的着陆时间的间隔小于 P ,那么如果选择了决策 x ,那么就一定不能选择决策 y ,即必须要选择决策 y 所决定的飞机的另一种着陆方式。

这样,我们就可以把到目前为止没有被访问过的节点,值设为 1 ,然后 DFS

若发现矛盾(即 DFS 过程中,发现某个节点所对应的飞机的另一种着陆方式的节点的值为 1 ),就将该节点(即前文提到的“到目前为止没有被访问过的节点”)所对应的飞机的另一种着陆方式的值设为 1 ,再 DFS

若还有矛盾,就无解了。

温馨提示(辛酸史):
- RE:邻接表数组要开到 (2n)2
- WA:按照我的二分习惯,应该是 while(l<=r),但我写成了 while(l……
- TL:注意每次判定,不用把邻接表全部 memset ,只要把需要用到的设为 0 就可以了。


Code

[cpp]
  1. #include   
  2. #include   
  3. #include   
  4.   
  5. using namespace std;  
  6.   
  7. inline int Max(int x,int y){  
  8.     return x>y?x:y;  
  9. }  
  10.   
  11. inline int abs(int x){  
  12.     return x>0?x:(-x);   
  13. }     
  14.   
  15. inline bool ok(int x,int y,int z){  
  16.     return abs(y-x)
  17. }  
  18.   
  19. int n;  
  20. int lat[20010],now[20010];  
  21. int head[401001],nxt[41000100],data[41000010];  
  22. int ss[401001];  
  23. bool vis[401001];  
  24. int cnt,maxn=0;  
  25.   
  26. inline void add(int x,int y){  
  27.     data[cnt]=y;nxt[cnt]=head[x];head[x]=cnt++;  
  28. }  
  29.   
  30. bool dfs(int now){  
  31.     if(((now&1)&&(vis[now-1]))||(vis[now+1]&&(!(now&1))))return false;  
  32.     if(vis[now])return true;  
  33.     ss[++maxn]=now;  
  34.     vis[now]=true;  
  35.     for(int i=head[now];i;i=nxt[i]){if(!dfs(data[i]))return false;}  
  36.     return true;  
  37. }  
  38.   
  39. bool pan(int x){  
  40.     for(int i=1;i<=n*2+10;i++)head[i]=vis[i]=ss[i]=0;   
  41.     for(int i=1;i<=n*n*4+10;i++)nxt[i]=data[i]=0;   
  42.     cnt=1;  
  43.     for(int i=1;i<=n;i++)  
  44.         for(int j=i+1;j<=n;j++){  
  45.             if(ok(now[i],lat[j],x)){add(2*i+1,2*j+1);add(2*j,2*i);}  
  46.             if(ok(lat[i],lat[j],x)){add(2*i,2*j+1);add(2*j,2*i+1);}  
  47.             if(ok(lat[i],now[j],x)){add(2*i,2*j);add(2*j+1,2*i+1);}  
  48.             if(ok(now[i],now[j],x)){add(2*i+1,2*j);add(2*j+1,2*i);}           
  49.         }  
  50.     for(int i=2;i<=n*2+1;i+=2)if(!vis[i]&&!vis[i+1]){  
  51.         maxn=0;  
  52.         if(!dfs(i)){  
  53.             for(int j=1;j<=maxn;j++)vis[ss[j]]=false;  
  54.             maxn=0;  
  55.             if(!dfs(i+1))return false;  
  56.         }  
  57.     }  
  58.     return true;  
  59. }  
  60.   
  61. int main(){  
  62.     while(scanf(“%d”,&n)!=EOF){  
  63.         int l=0,r=0,ans=0;   
  64.         for(int i=1;i<=n;i++){  
  65.             scanf(”%d%d”,&now[i],&lat[i]);  
  66.             r=Max(now[i],r);  
  67.             r=Max(lat[i],r);  
  68.         }  
  69.         while(l<=r){  
  70.             int mid=((long long)l+r)/2;  
  71.             bool flag=pan(mid);  
  72.             if(flag){  
  73.                 ans=Max(ans,mid);  
  74.                 if(l!=mid+1)l=mid+1;  
  75.                 else break;  
  76.             }  
  77.             else{  
  78.                 if(r!=mid-1)r=mid-1;  
  79.                 else break;  
  80.             }  
  81.         }  
  82.         printf(”%d\n”,ans);  
  83.     }  
  84.     return 0;  
  85. }  

你可能感兴趣的:(题解,二分与补集转化,LA)