Poj--2723(2-SAT,二分)

2014-10-21 16:24:18

思路:传统的2-SAT题,自己YY了建图,也是醉了。写完这题坚定了二分区间左闭右开的写法。

  方法:首先二分能打开的门数,然后建图:枚举每一对门(A,B),不妨令A门比B门先遇到,(以A、A’ 来分别表示打开A的第一个锁和第二个锁)找矛盾建“必须”边,如:A和B’的钥匙是一对的,那么打开了A就打不开B’,则建边:A->B,B'->A'。然后就可以2-SAT做了。

  1 /*************************************************************************
  2     > File Name: 2723.cpp
  3     > Author: Nature
  4     > Mail: 564374850@qq.com 
  5     > Created Time: Tue 21 Oct 2014 03:57:35 PM CST
  6 ************************************************************************/
  7 
  8 #include <cstdio>
  9 #include <cstring>
 10 #include <cstdlib>
 11 #include <cmath>
 12 #include <vector>
 13 #include <map>
 14 #include <set>
 15 #include <stack>
 16 #include <queue>
 17 #include <iostream>
 18 #include <algorithm>
 19 using namespace std;
 20 #define lp (p << 1)
 21 #define rp (p << 1|1)
 22 #define getmid(l,r) (l + (r - l) / 2)
 23 #define MP(a,b) make_pair(a,b)
 24 typedef long long ll;
 25 const int INF = 1 << 30;
 26 const int maxn = 1 << 12;
 27 
 28 int N,M;
 29 int mp[1 << 11];
 30 int door[1 << 11][2];
 31 int first[maxn],next[maxn * maxn],ver[maxn * maxn],ecnt;
 32 int low[maxn],dfn[maxn],sc[maxn],scnt,tot;
 33 stack<int> S;
 34 
 35 void Add_edge(int u,int v){
 36     next[++ecnt] = first[u];
 37     ver[ecnt] = v;
 38     first[u] = ecnt;
 39 }
 40 
 41 void Build_graph(int val){
 42     for(int i = 0; i < val; ++i){
 43         for(int j = i + 1; j < val; ++j){
 44             if(mp[door[i][0]] == door[j][0]){
 45                 Add_edge(i * 2,j * 2 + 1);
 46                 Add_edge(j * 2,i * 2 + 1);
 47             }
 48             if(mp[door[i][0]] == door[j][1]){
 49                 Add_edge(i * 2,j * 2);
 50                 Add_edge(j * 2 + 1,i * 2 + 1);
 51             }
 52             if(mp[door[i][1]] == door[j][0]){
 53                 Add_edge(i * 2 + 1,j * 2 + 1);
 54                 Add_edge(j * 2,i * 2);
 55             }
 56             if(mp[door[i][1]] == door[j][1]){
 57                 Add_edge(i * 2 + 1,j * 2);
 58                 Add_edge(j * 2 + 1,i * 2);
 59             }
 60         }
 61     }
 62 }
 63 
 64 void Dfs(int p){
 65     dfn[p] = low[p] = ++tot;
 66     S.push(p);
 67     for(int i = first[p]; i != -1; i = next[i]){
 68         int v = ver[i];
 69         if(!dfn[v]){
 70             Dfs(v);
 71             low[p] = min(low[p],low[v]);
 72         }
 73         else if(!sc[v]){
 74             low[p] = min(low[p],dfn[v]);
 75         }
 76     }
 77     if(low[p] == dfn[p]){
 78         ++scnt;
 79         while(1){
 80             int x = S.top();
 81             S.pop();
 82             sc[x] = scnt;
 83             if(x == p) break;
 84         }
 85     }
 86 }
 87 
 88 void Tarjan(){
 89     memset(low,0,sizeof(low));
 90     memset(dfn,0,sizeof(dfn));
 91     memset(sc,0,sizeof(sc));
 92     while(!S.empty()) S.pop();
 93     scnt = tot = 0;
 94     for(int i = 0; i < 2 * M; ++i)
 95         if(!dfn[i]) Dfs(i);
 96 }
 97 
 98 void Init(){
 99     memset(first,-1,sizeof(first));
100     ecnt = 0;
101 }
102 
103 bool Solve(int val){
104     Init();
105     Build_graph(val);
106     Tarjan();
107     //check
108     for(int i = 0; i < 2 * M; i += 2)
109         if(sc[i] == sc[i + 1])
110             return false;
111     return true;
112 }
113 
114 int main(){
115     int a,b;
116     while(scanf("%d%d",&N,&M) != EOF){
117         if(!N && !M) break;
118         for(int i = 0; i < N; ++i){
119             scanf("%d%d",&a,&b);
120             mp[a] = b;
121             mp[b] = a;
122         }
123         for(int i = 0; i < M; ++i){
124             scanf("%d%d",&a,&b);
125             door[i][0] = a;
126             door[i][1] = b;
127         }
128         int mid,ans,l = 1,r = M + 1;
129         while(l < r){
130             mid = getmid(l,r);
131             if(Solve(mid)){
132                 ans = mid;
133                 l = mid + 1;
134             }
135             else r = mid;
136         }
137         printf("%d\n",ans);
138     }
139     return 0;
140 }

 

posted @ 2014-10-21 16:34  Naturain  阅读(94)  评论(0)    收藏  举报