poj 2723 Get Luffy Out (2 -sat + 二分)

http://poj.org/problem?id=2723

题意:

有2n把钥匙,分成2组,给你每组的钥匙信息,并且每组的钥匙只能用一个。

有m个门,每个门有2个锁,只要打开一个锁这个门就开了。(顺序遇见m个门)

问你最多能够打开多少个门。

题解:

通过这道题 ,对 2-sat  有了 进一步的了解。。。。。

2-SAT主要是寻找不相容的点(建图),首先是

我们把钥匙分为 选和不选,A和 !A

对于 第一类 : 没两把钥匙 ,a和b  ( 必然关系 ) 选 a 不选 b(a->!b) ,选 b 不选 a(b->!a);

 对于 第二类:

每一扇门  有 a 锁和 b 锁,不开a 必开 b (!a->b),,不开b 必开 a(!b->a),///一开始 建图减成了 a-> !b  和 b-> !a (这样是 不对的

因为每扇门 至少要开一把锁, 我们要找的是 必须的 关系
)

因为 门 是 顺序的 ,所以要  二分枚举。

 

  1 #include<cstdio>
  2  #include<cstring>
  3  #include<cmath>
  4  #include<iostream>
  5  #include<algorithm>
  6  #include< set>
  7  #include<map>
  8  #include<queue>
  9  #include<vector>
 10  #include< string>
 11   #define Min(a,b) a<b?a:b
 12   #define Max(a,b) a>b?a:b
 13   #define CL(a,num) memset(a,num,sizeof(a));
 14   #define eps  1e-12
 15   #define inf 100000000
 16   #define mx 1<<60
 17   #define ll   __int64
 18   const  double pi  = acos(- 1.0);
 19   const  int maxn =  5000;
 20   using  namespace std;
 21   int  top,num,bcnt,belong[maxn],instack[maxn],stack[maxn],dfn[maxn],low[maxn];
 22   int n ,m;
 23   int a[maxn],b[maxn],c[maxn],d[maxn];
 24   struct pnode
 25  {
 26       int to;
 27       int next;
 28  }p[maxn* 2];
 29 
 30   int cnt ,next[maxn];
 31   void add( int u, int v)
 32  {
 33      p[cnt].to = v;
 34      p[cnt].next  = next[u];
 35      next[u] = cnt++;
 36 
 37  }
 38   void tarjan( int i)
 39  {
 40       int j,k;
 41      dfn[i] = low[i] = ++num;
 42      stack[++top] = i;
 43      instack[i] =  1;
 44       for(k = next[i] ; k != - 1;k = p[k].next)
 45      {
 46 
 47           j = p[k].to ;
 48           if(!dfn[j])
 49          {
 50              tarjan(j);
 51               if(low[j] < low[i]) low[i] = low[j] ;
 52          }
 53           else
 54          {
 55               if(instack[j] && dfn[j] < low[i]) low[i] = dfn[j] ;
 56          }
 57 
 58      }
 59       if(dfn[i] == low[i])
 60      {
 61          bcnt++;
 62           do
 63          {
 64              j = stack[top--];
 65              instack[j] =  0 ;
 66              belong[j] = bcnt ;
 67          } while(j != i);
 68      }
 69  }
 70   void solve()
 71  {
 72       int i, l;
 73       for(i = 0 ; i <= n* 4;i++)
 74      {
 75          dfn[i] = low[i] = instack[i] = stack[i] = belong[i] =  0;
 76      }
 77      top = bcnt = num =  0;
 78       for(i =  0 ; i < n* 4;i++)
 79      {
 80           if(!dfn[i])tarjan(i);
 81      }
 82 
 83 
 84 
 85  }
 86   void init()
 87  {
 88      CL(next,- 1);
 89      cnt =  0 ;
 90 
 91  }
 92   bool judge()
 93  {
 94       for( int i =  0 ; i <  2*n;i++)
 95      {
 96           if(belong[i] == belong[i +  2*n])
 97            return  false ;
 98      }
 99       return  true ;
100  }
101   int main()
102  {
103       int i,j;
104 
105       // freopen("data.txt","r",stdin) ;
106 
107      while(scanf( " %d%d ",&n,&m),n+m)
108     {
109 
110          for(i =  1 ;i <= n;i++)
111         {
112             scanf( " %d%d ",&a[i],&b[i]);
113 
114         }
115          for(i =  1;i <= m;i++)
116         {
117             scanf( " %d%d ",&c[i],&d[i]);
118 
119         }
120          int l =  0,r = m ;
121          int ans =  0 ;
122          while(l <= r)
123         {
124             init();
125              int mid = (l+r)>> 1;
126              for(i =  1; i<= n;i++)
127             {
128                 add(a[i],b[i] + n* 2);
129                 add(b[i],a[i] + n* 2);
130             }
131              for(i =  1;i <= mid;i++)
132             {
133                 add(c[i] + n* 2,d[i] );
134                 add(d[i] + n* 2,c[i] );
135             }
136             solve() ;
137              if(judge())
138             {
139 
140                  l = mid +  1;
141                  ans = mid ;
142             }
143              else  r = mid -  1;
144         }
145         printf( " %d\n ",ans);
146     }
147  }

 

你可能感兴趣的:(get)