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 }

浙公网安备 33010602011771号