• 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;
    }
             
    

  • 相关阅读:
    进程、线程
    timer控件、三级联动
    用户控件、动态创建添加
    打印控件
    窗体移动和阴影,对话框控件
    winform listview控件
    winform打开唯一窗体、构造函数传值
    菜单和工具栏
    winform公共控件
    hibernate中各种包的添加
  • 原文地址:https://www.cnblogs.com/csnd/p/12063009.html
Copyright © 2020-2023  润新知