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  }

 

posted @ 2012-09-05 22:18  Szz  阅读(224)  评论(0编辑  收藏  举报