zoukankan      html  css  js  c++  java
  • 2-sat 问题 【例题 Flags(2-sat+线段树优化建图)】

    序:

    模拟赛考了一道 2-sat 问题。之前从来没听过……

    考完才发现其实这个东东只要一个小小的 tarjan 求强连通分量就搞定了。

    这个方法真是巧妙啊,拿来讲讲。

    What is it? [・_・?]

    这个算法是为了应对一些这样的条件:x1 与 x1 中至少有一个成立

    算法:

    既然是“2"-sat,那就要充分发挥 “two” 的优势,由于x1限制关系,有一些点我们选了后,有一些点就不能选了,那我们就只能选另一个点了满足 x2。

    我们把 a 想它必须选的点 b 连有向边,这样就构成了一个图,判定的话,判断是否有两个不能同时存在的点在一个强连通分量中就好了!

    这有一位大佬写的比我更好 OTZ

    当然重点是讲模拟赛的题!

    例题  Flags:

    传送门

    题目大意:数轴上有 n 个旗子,第 i 个可以插在坐标 xi 或者 yi,最大化两两旗子之间的最小距离。

    题解:

    我们可以二分答案,转化为一个 2-sat 问题。

    二分最小距离 d,那么一个点 a 向左向右 d 的 b 点都不能选,那么选了 a 就必须选 b 的另一个位置,然后我们连边,最后判断是不是有一个点的两个位置是不是在一个强连通分量里,在则不能,否则可以。

    这题还有一个点就是如果直接建边的话,就有 $n^2$ 条边,你会发现这题一个点的连边都是连续的,那就不妨线段树优化建图。具体思想戳这里

    CODE:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<stack>
      4 #include<algorithm>
      5 #include<cstring>
      6 using namespace std;
      7  
      8 int v[100005];
      9 int n,x,y,tot=0,h[100005];
     10 int scc[100005],dfn[100005],low[100005],C,cnt;
     11 bool vis[100005];
     12 struct Edge{
     13     int x,next;
     14 }e[5000000];
     15 pair<int,int> a[20005];
     16 stack<int> s;
     17  
     18 inline void add_edge(int x,int y){
     19     e[++tot].x=y;
     20     e[tot].next=h[x],h[x]=tot;
     21 }
     22  
     23 void tarjan(int x){
     24     dfn[x]=low[x]=++cnt;
     25     s.push(x),vis[x]=true;
     26     for(int i=h[x];~i;i=e[i].next){
     27         if(!dfn[e[i].x]){
     28             tarjan(e[i].x),low[x]=min(low[x],low[e[i].x]);
     29         }else if(vis[e[i].x]){
     30             low[x]=min(low[x],dfn[e[i].x]);
     31         }   
     32     }
     33     if(dfn[x]==low[x]){
     34         C++;
     35         int tmp;
     36         for(;;){
     37             tmp=s.top();
     38             vis[tmp]=false,scc[tmp]=C;
     39             s.pop();
     40             if(tmp==x)break;
     41         }
     42     }
     43 }
     44  
     45 void build(int o,int l,int r){
     46     if(r-l==1){
     47         add_edge(o+n*2,a[l].second^1);
     48         return;
     49     }
     50     add_edge(o+n*2,(o<<1)+n*2);
     51     add_edge(o+n*2,(o<<1|1)+n*2);
     52     int mid=l+r>>1;
     53     build(o<<1,l,mid),build(o<<1|1,mid,r);
     54 }
     55  
     56 void link(int o,int l,int r,int x,int y,int a){
     57     if(l>=x&&r<=y){
     58         add_edge(a,o+n*2);
     59         return;
     60     }
     61     int mid=l+r>>1;
     62     if(x<mid)link(o<<1,l,mid,x,y,a);
     63     if(y>mid)link(o<<1|1,mid,r,x,y,a);
     64 }
     65  
     66 inline pair<int,int> get(int x,int len){
     67     int l=0,r=x;
     68     pair<int,int> ans;
     69     while(l<r){
     70         int mid=l+r>>1;
     71         if(a[x].first-a[mid].first<len)r=mid;
     72         else l=mid+1;
     73     }
     74     ans.first=l;
     75     l=x,r=n*2-1;
     76     while(l<r){
     77         int mid=l+r+1>>1;
     78         if(a[mid].first-a[x].first<len)l=mid;
     79         else r=mid-1;
     80     }
     81     ans.second=l;
     82     return ans;
     83 }
     84  
     85 inline bool check(int d){
     86     memset(scc,0,sizeof(scc));
     87     memset(dfn,0,sizeof(dfn));
     88     memset(low,0,sizeof(low));
     89     memset(h,-1,sizeof(h)),tot=0;
     90     build(1,0,n*2);
     91     for(int i=0;i<n*2;i++){
     92         int id=a[i].second;
     93         pair<int,int> x=get(i,d);
     94         if(i<x.second)link(1,0,n*2,i+1,x.second+1,id);
     95         if(x.first<i)link(1,0,n*2,x.first,i,id);
     96     }
     97     C=cnt=0;
     98     for(int i=0;i<n*2;i++)if(!dfn[i])tarjan(i);
     99     for(int i=0;i<n*2;i++)
    100         if(scc[a[i].second]==scc[a[i].second^1])return false;
    101     return true;
    102 }
    103  
    104 int main(){
    105     scanf("%d",&n);
    106     for(int i=0;i<n;i++){
    107         scanf("%d%d",&x,&y);
    108         a[2*i+1]=make_pair(x,2*i+1);
    109         a[2*i]=make_pair(y,2*i);
    110     }
    111     sort(a,a+n*2);
    112     int l=0,r=1000000000;
    113     while(l<r){
    114         int mid=l+r+1>>1;
    115         if(check(mid))l=mid;
    116         else r=mid-1;
    117     }
    118     printf("%d",l);
    119 }
  • 相关阅读:
    Android SDK Manager下载和更新失败的解决方法!!!
    java反射详解
    Maven--->学习心得--->maven project的标准目录结构
    Maven--->学习心得--->maven 的生命周期(LifeCycle)
    Maven--->学习心得--->maven的配置文件pom.xml
    硬盘管理
    JavaScript------>调试JavaScript代码------>使用 浏览器 中的 “开发者工具” 来调试
    java框架---->spring框架---->使用实例
    step5--->往工程中添加Spring框架---->修改maven的配置文件pom.xml,向工程中添加spring框架的某些模块
    JavaScript------第一课
  • 原文地址:https://www.cnblogs.com/ezoiLZH/p/9465026.html
Copyright © 2011-2022 走看看