【LA3211 训练指南】飞机调度 【2-sat】

题意

  有n嫁飞机需要着陆。每架飞机都可以选择“早着陆”和“晚着陆”两种方式之一,且必须选择一种。第i架飞机的早着陆时间为Ei,晚着陆时间为Li,不得在其他时间着陆。你的任务是为这些飞机安排着陆方式,使得整个着陆计划尽量安全。话句话说,如果把所有飞机的实际着陆时间按照从早到晚的顺序排列,相邻两个着陆时间间隔的最小值(称为安全间隔)应尽量大。

分析

  看到最小值最大立刻会想到二分。大体思路很好想,我们二分这个安全间隔,然后判断是否可行。那么这个题的难点就变为如何判断这个安全间隔是否可行。

  n架飞机,每架飞机要么选择早起飞要么选择晚起飞,对应着2-sat问题中n个布尔型变量每个变量要么为真,要么为假。那么那m个限制条件是什么呢? 

  我们假设当前二分的安全间隔是P,那么如果两个时间小于P,则说明两个时间不能同时选择。比如说Ei和Lj的时间差小于P,则说明Ei和Lj不能同时选择。所以要么选择Li和Lj,要么选择Ei和Ej,要么选择Li和Ej。也就是说,xi晚起飞或者xj早起飞。到这里这个题就完全转化为了2-sat问题。

  下面是AC的代码

  

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5 #include <vector>
 6 #include <cmath>
 7 
 8 using namespace std;
 9 const int maxn=2000+10;
10 struct TwoSAT{
11     int n;
12     vector<int>G[2*maxn];
13     bool mark[maxn*2];
14     int S[maxn*2],c;
15     bool dfs(int x){
16         if(mark[x^1])return false;
17         if(mark[x])return true;
18         mark[x]=true;
19         S[c++]=x;
20         for(int i=0;i<G[x].size();i++){
21             if(!dfs(G[x][i]))return false;
22         }
23         return true;
24     }
25     void init(int n){
26         this->n=n;
27         for(int i=0;i<n*2;i++)G[i].clear();
28         memset(mark,0,sizeof(mark));
29     }
30     void add_clause(int x,int xval,int y,int yval){
31         x=x*2+xval;
32         y=y*2+yval;
33         G[x^1].push_back(y);
34         G[y^1].push_back(x);
35     }
36 
37     bool solve(){
38         for(int i=0;i<n*2;i+=2){
39             if(!mark[i]&&!mark[i+1]){
40                 c=0;
41                 if(!dfs(i)){
42                     while(c>0)mark[S[--c]]=false;
43                     if(!dfs(i+1))return false;
44                 }
45             }
46         }
47         return true;
48     }
49 }solver;
50 int n,T[maxn][2];
51 bool test(int diff){
52     solver.init(n);
53     for(int i=0;i<n;i++){
54         for(int a=0;a<2;a++){
55             for(int j=i+1;j<n;j++){
56                 for(int b=0;b<2;b++){
57                     if(abs(T[i][a]-T[j][b])<diff)solver.add_clause(i,a^1,j,b^1);
58                 }
59             }
60         }
61     }
62     return solver.solve();
63 }
64 int main(){
65     while(scanf("%d",&n)!=EOF&&n){
66         int L=0,R=0;
67         for(int i=0;i<n;i++){
68             for(int a=0;a<2;a++){
69                 scanf("%d",&T[i][a]);
70                 R=max(R,T[i][a]);
71             }
72         }
73         while(L<R){
74             int M=L+(R-L+1)/2;
75            // cout<<L<<" "<<R<<endl;
76             if(test(M))L=M;
77             else
78                 R=M-1;
79         }
80         printf("%d
",L);
81     }
82 return 0;
83 }
View Code
原文地址:https://www.cnblogs.com/LQLlulu/p/9310922.html