插头DP就暂时那么地儿吧,纠结学什么的结果是学这个2-SAT本来以为得多难,下了好大决心,结果只是照着刘汝佳的书就看懂代码和思想了~
说这个题的思路:引用书上的话就是,最小值尽量大的典型做法就是二分查找,这样,原来的问题就转化成了判定问题:是否存在一个调度方案,使得相邻两个着陆时间总不小于P,进一步转化为:任意两个着陆时间差总不小于P。即唯一的限制就是:时间差小于P的两个两个着陆时间不能同时满足。
模板没啥好讲的,简直比插头Dp简单的不是一点半点
/************
uva1146
2016.1.11
0kb 446 ms
C++ 4.8.2
************/
#include <iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
#define maxn 2005
struct TwoSAT{
int n;
vector<int>G[maxn*2];
bool mark[maxn*2];
int S[maxn*2],c;
bool dfs(int x){
if(mark[x^1]) return false;
if(mark[x]) return true;
mark[x]=true;
S[c++]=x;
for(int i=0;i<G[x].size();i++)
if(!dfs(G[x][i])) return false;
return true;
}
void init(int n){
this->n=n;
for(int i=0;i<(n<<1);i++) G[i].clear();
memset(mark,0,sizeof(mark));
}
void add_clause(int x,int xval,int y,int yval){
x=x*2+xval;
y=y*2+yval;
G[x^1].push_back(y);
G[y^1].push_back(x);
}
bool solve(){
for(int i=0;i<n*2;i+=2)
if(!mark[i]&&!mark[i+1]){
c=0;
if(!dfs(i)){
while(c>0) mark[S[--c]]=false;
if(!dfs(i+1)) return false;
}
}
return true;
}
}solver;
int n,T[maxn][2];
bool test(int diff){
solver.init(n);
for(int i=0;i<n;i++)
for(int a=0;a<2;a++)
for(int j=i+1;j<n;j++)
for(int b=0;b<2;b++)
if(abs(T[i][a]-T[j][b])<diff)
solver.add_clause(i,a^1,j,b^1);
return solver.solve();
}
int main()
{
//freopen("cin.txt","r",stdin);
while(~scanf("%d",&n)&&n)
{
int L=0,R=0;
for(int i=0;i<n;i++)
for(int a=0;a<2;a++)
{
scanf("%d",&T[i][a]);
R=max(R,T[i][a]);
}
while(L<R){
int M=L+(R+1-L)/2;
if(test(M)) L=M;
else R=M-1;
}
printf("%d\n",L);
}
return 0;
}