UVALive - 3211 (2-SAT + 二分)
阿新 • • 發佈:2019-01-31
sin using 必須 eof memset 兩個 最大值 mod abs
layout: post
title: 訓練指南 UVALive - 3211 (2-SAT + 二分)
author: "luowentaoaa"
catalog: true
mathjax: true
tags:
- 2-SAT
- 圖論
- 訓練指南
Now or later
UVALive - 3211
題意
n架飛機,每架可選擇兩個著落時間。安排一個著陸時間表,使得著陸間隔的最小值最大
題解
二分查找最大值P,每次都用2—SAT判斷是否可行。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=998244353; const int maxn=1e6+50; const ll inf=0x3f3f3f3f3f3f3f3fLL; 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*2;i++)G[i].clear(); memset(mark,0,sizeof(mark)); } /// x=xval or y= yval; void add_caluse(int x,int xval,int y,int yval){ x=x*2+xval; y=y*2+yval; G[x^1].push_back(y);///如果x為真 那麽y必須為假; G[y^1].push_back(x);///如果y為真 那麽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; } }; int n,T[maxn][2]; TwoSAT solver; 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_caluse(i,a^1,j,b^1); return solver.solve(); } int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); std::cout.tie(0); while(cin>>n&&n){ int L=0,R=0; for(int i=0;i<n;i++)for(int a=0;a<2;a++){ cin>>T[i][a]; R=max(T[i][a],R); } int ans=0; while(L<=R){ int mid=(L+R)/2; if(test(mid)){ ans=mid; L=mid+1; } else R=mid-1; } cout<<ans<<endl; } return 0; }
UVALive - 3211 (2-SAT + 二分)