zoukankan      html  css  js  c++  java
  • hdu1816 + POJ 2723开锁(二分+2sat)

    题意:
         有m层门,我们在最外层,我们要一层一层的进,每一层上有两把锁,我们只要开启其中的一把们就会开,我们有n组钥匙,每组两把,我们只能用其中的一把,用完后第二把瞬间就会消失,问你最多能开到多少层们。

    思路:

          果断二分+2sat,现在我们来看下怎么建边,首先我们把每把钥匙用看成a,不用看成~a ,对于没一组钥匙,我们不能同时选择两个,所以有 x ->~y ,y -> ~x,对于门,我们每次至少选择开一个,所以有 ~x -> y ,~y -> x,就这样二分每次重新建图就行了,顺便说下POJ2723 ,跟这个题目几乎差不多,但是唯一的区别就是那个题目每组钥匙不会重复,这个有可能是同一把钥匙属于多个组,如果用这个题目的代码直接去交POJ2723,直接就可以AC了,钥匙反过来就不一定了,因为那个题目既然说是一把钥匙最多只出现在一组,那么就没有必要把每把钥匙拆成a 和 ~a ,而是把每组的钥匙拆成 a ~a,这样就节省了点数和时间,同时也没有必要建 x ->~y y->~x,这样也节省的边,如果是那么做的,那么到这个题目上就WA了,所以我说这个代码粘到那个代码上肯定AC,反过来就不一定了。


    #include<stdio.h>
    #include<string.h>
    #include<stack>
    
    #define N_node 5000
    #define N_edge 50000
    
    using namespace std;
    
    typedef struct
    {
       int to ,next;
    }STAR;
    
    STAR E1[N_edge] ,E2[N_edge];
    int list1[N_node] ,list2[N_node] ,tot;
    int Belong[N_node] ,cnt;
    int mark[N_node];
    int D[N_node][2] ,A[N_node][2];
    int id[N_node];
    stack<int>st;
    
    void add(int a ,int b)
    {
       E1[++tot].to = b;
       E1[tot].next = list1[a];
       list1[a] = tot;
       a = a + b ,b = a - b ,a = a - b;
       E2[tot].to = b;
       E2[tot].next = list2[a];
       list2[a] = tot;
    }
    
    void DFS1(int s)
    {
       mark[s] = 1;
       for(int k = list1[s] ;k ;k = E1[k].next)
       if(!mark[E1[k].to]) DFS1(E1[k].to);
       st.push(s);
    }
    
    void DFS2(int s)
    {
       mark[s] = 1;
       Belong[s] = cnt;
       for(int k = list2[s] ;k ;k = E2[k].next)
       if(!mark[E2[k].to]) DFS2(E2[k].to);
    }
    
    bool ok(int mid ,int n)
    {
       memset(list1 ,0 ,sizeof(list1));
       memset(list2 ,0 ,sizeof(list2));
       tot = 1;
       for(int i = 1 ; i<= n/2 ;i ++)
       {
          int x = A[i][0] * 2 ,xx = A[i][0] * 2 + 1;
          int y = A[i][1] * 2 ,yy = A[i][1] * 2 + 1;
          add(x ,yy) ,add(y ,xx);
       }
         
       for(int i = 1 ;i <= mid ;i ++)
       { 
          int x = D[i][0] * 2 ,xx = D[i][0] * 2 + 1;
          int y = D[i][1] * 2 ,yy = D[i][1] * 2 + 1;
          add(xx ,y) ,add(yy ,x);
       }
       memset(mark ,0 ,sizeof(mark));
       while(!st.empty()) st.pop();
       for(int i = 0 ;i < n * 2 ;i ++)
       if(!mark[i]) DFS1(i);
       memset(mark ,0 ,sizeof(mark));
       cnt = 0;
       while(!st.empty())
       {
          int xin = st.top();
          st.pop();
          if(mark[xin]) continue;
          cnt ++;
          DFS2(xin);
       }
       int mk = 0;
       for(int i = 0 ;i < n * 2 && !mk;i += 2)
       if(Belong[i] == Belong[i^1]) mk = 1;
       return !mk;
    }
    
    int main ()
    {
       int i ,n ,m ,a ,b;
       while(~scanf("%d %d" ,&n ,&m) && n + m)
       {
          for(i = 1 ;i <= n ;i ++)
          {
             scanf("%d %d" ,&a ,&b);
             A[i][0] = a ,A[i][1] = b;
          }
          for(i = 1 ;i <= m ;i ++)
          scanf("%d %d" ,&D[i][0] ,&D[i][1]); 
          int low ,up , mid ,ans = 0;
          low = 0 ,up = m ,n *= 2;
          while(low <= up)
          {
             mid = (low + up) >> 1;
             if(ok(mid ,n))
             ans = mid ,low = mid + 1;
             else up = mid - 1;
          }
          printf("%d
    " ,ans);
       }
       return 0;
    }
             
    

  • 相关阅读:
    springcloud 项目源码 微服务 分布式 Activiti6 工作流 vue.js html 跨域 前后分离
    springcloud 项目源码 微服务 分布式 Activiti6 工作流 vue.js html 跨域 前后分离
    OA办公系统 Springboot Activiti6 工作流 集成代码生成器 vue.js 前后分离 跨域
    java企业官网源码 自适应响应式 freemarker 静态引擎 SSM 框架
    java OA办公系统源码 Springboot Activiti工作流 vue.js 前后分离 集成代码生成器
    springcloud 项目源码 微服务 分布式 Activiti6 工作流 vue.js html 跨域 前后分离
    java 视频播放 弹幕技术 视频弹幕 视频截图 springmvc mybatis SSM
    最后阶段总结
    第二阶段学习总结
    第一阶段学习总结
  • 原文地址:https://www.cnblogs.com/csnd/p/12063010.html
Copyright © 2011-2022 走看看