Now or later UVA - 1146
题意:
有n架飞机需要着陆。每架飞机都可以选择“早着陆”和“晚着陆”两种方式之一,且必须选择一种。第 i i i架飞机的早着陆时间为 E i E_i Ei,晚着陆时间为 L i L_i Li,不得在其他时间着陆。你的任务是为这些飞机安排着陆方式,使得整个着陆计划尽量安全。换句话说,如果把所有飞机的实际着陆时间按照从早到晚的顺序排列,相邻两个着陆时间间隔的最小值(称为安全间隔)应尽量大。
思路:
看到最后一句话,显然是二分的套路。
那么现在问题是怎么安排:
- 可以二分答案,之后按照这个答案去check。(二分的中间值为mid)
- 对于一个飞机有 两个取值, 很容易联想到可以用 2-sat。
- 那么现在就是如何构造限制。其实分析也可以知道。两个飞机之间的着陆时间间隔 要大于等于 mid。(
假如<mid
,就要想办法让它们不成立,即限制)
假如两个着陆时间点的时间间隔,
小于mid
,那么就取另外两个方向
去限制 。
反思:
- 考虑下面两种二分的写法。。。。。wa的教训。
int l=0,r=0,ans;
fori(i,0,n)cin>>ex[i][0]>>ex[i][1],r=max(r,max(ex[i][0],ex[i][1]));
while(l<r){
int mid=l+(r-l+1)/2;
if(work(mid)){
ans=mid;l=mid;//l=mid+1;
}else r=mid-1;//r=mid-1;
}
fori(i,0,n)cin>>ex[i][0]>>ex[i][1],r=max(r,max(ex[i][0],ex[i][1]));
while(l<=r){
int mid=(l+r)>>1;//l+(r-l+1)/2;
if(work(mid)){
ans=mid;l=mid+1;//l=mid;
}else r=mid-1;
}
- 注意二分的上下限。
AC
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <stack>
#include <cmath>
#define pb push_back
#define fzhead EDGE(int _to, int _next)
#define fzbody to(_to), next(_next)
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define fori(i,x,y) for(int i=(x); i<(y); i++)
using namespace std;
const int maxn=2000+10;
const int maxm=2000*2000+10;
struct EDGE{
int to,next;
EDGE(){}
fzhead:fzbody{}
}e[2*maxm*2];
int head[2*maxn],tot;
bool mark[maxn*2];
///int s
stack<int>s;
void add(int bg, int to){
e[tot]=EDGE(to,head[bg]);
head[bg]=tot++;
}
void add_clause(int x, int xval, int y, int yval){
x=x*2+xval;
y=y*2+yval;
add(x^1,y);
add(y^1,x);
}
bool dfs(int x){
if(mark[x^1])return false;
if(mark[x])return true;
mark[x]=true;
s.push(x);
for(int i=head[x]; i!=-1; i=e[i].next){
int v=e[i].to;
if(!dfs(v))return false;
}
return true;
}
int n;
bool solve(){
for(int i=0; i<2*n; i+=2){//fori(i,0,2*n){
if(!mark[i] && !mark[i+1]){
while(!s.empty())s.pop();
if(!dfs(i)){
while(!s.empty())mark[s.top()] = false,s.pop();
if(!dfs(i+1))return false;
}
}
}
return true;
}
void init(){
mst(mark,0);tot=2;
mst(head,-1);
while(!s.empty())s.pop();
}
int ex[maxn][2];
bool work(int dis){
init();
fori(i,0,n)fori(a,0,2)fori(j,i+1,n)fori(b,0,2){
if(abs(ex[i][a]-ex[j][b])<dis)add_clause(i,a^1,j,b^1);
}
return solve();
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
while(cin>>n){
int l=0,r=0,ans;
fori(i,0,n)cin>>ex[i][0]>>ex[i][1],r=max(r,max(ex[i][0],ex[i][1]));
while(l<=r){
int mid=(l+r)>>1;//l+(r-l+1)/2;
if(work(mid)){
ans=mid;l=mid+1;//l=mid;
}else r=mid-1;
}
cout<<ans<<endl;
}
return 0;
}