D45 2-SAT+二分 UVA1146 Now or later

董晓發表於2024-08-17

影片連結:

D40 2-SAT POJ3683 Priest John's Busiest Day - 董曉 - 部落格園 (cnblogs.com)

UVA1146 Now or later - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)

// 2-SAT+二分 O(n*n*logt)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

const int N=4010;
int n,a[N][2];
vector<int> v[N]; //鄰接表
int dfn[N],low[N],scc[N],stk[N],tim,top,cnt;

void tarjan(int x){
  dfn[x]=low[x]=++tim;
  stk[++top]=x;
  for(int y:v[x]){
    if(!dfn[y]){ //若y尚未訪問
      tarjan(y);
      low[x]=min(low[x],low[y]);
    }
    else if(!scc[y]) //若y已訪問且未處理
      low[x]=min(low[x],dfn[y]);
  }
  
  if(low[x]==dfn[x]){ //若x是SCC的根
    ++cnt;
    for(int y=-1;y!=x;)
      scc[y=stk[top--]]=cnt;
  }
}
bool check(int mid){
  for(int i=1;i<=2*n;++i) v[i].clear();
  memset(dfn,0,sizeof dfn);
  memset(low,0,sizeof low);
  memset(scc,0,sizeof scc);
  tim=top=cnt=0;
  for(int i=1;i<=n;++i){ //建圖
    for(int j=i+1;j<=n;++j){
      if(abs(a[i][0]-a[j][0])<mid)
        v[i].push_back(j+n), //i→j'
        v[j].push_back(i+n); //j→i'
      if(abs(a[i][0]-a[j][1])<mid)
        v[i].push_back(j),    //i→j
        v[j+n].push_back(i+n);//j'→i'        
      if(abs(a[i][1]-a[j][0])<mid)
        v[i+n].push_back(j+n),//i'→j'
        v[j].push_back(i);    //j→i
      if(abs(a[i][1]-a[j][1])<mid)
        v[i+n].push_back(j), //i'→j
        v[j+n].push_back(i); //j'→i      
    }
  }
  for(int i=1;i<=2*n;++i) if(!dfn[i])tarjan(i);
  for(int i=1;i<=n;++i)
    if(scc[i]==scc[i+n]) return 0;
  return 1;
}
int main(){
  while(scanf("%d",&n)!=EOF){
    for(int i=1;i<=n;++i)
      scanf("%d%d",&a[i][0],&a[i][1]);
      
    int l=0,r=1e7+1,mid; //二分時間
    while(l+1<r){ 
      mid=(l+r)>>1;
      check(mid)?l=mid:r=mid;
    }
    printf("%d\n",l);   
  }
}

相關文章