POJ-2723(2-SAT)

来源:互联网 发布:网络借钱平台 编辑:程序博客网 时间:2024/05/17 22:03

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

第5道2-SAT,一开始没想起来怎么构造,然后想到了用mark[2i]表示是否开gate[i]的左边一把锁lock[2i],用mark[2i+1]表示是否开gate[i]的右边一把锁lock[2i+1],则如果lock[x]和lock[y]需要的钥匙不同且lock[x]和lock[y]需要的钥匙在同一串上(一串钥匙有两个),则构成条件开lock[x]或者开lock[y],注意到开锁要求必须从gate[0]到gate[i-1]都开完了才能开gate[i]上的锁,因此我们可以通过二分搜索满足要求的最大开门数量,毕竟如果能开N扇门,则一定能开N-1扇门。


#include <cstdio>#include <cstring>#include <vector>using namespace std;const int MAX_N = 1 << 10;const int MAX_M = 1 << 11;int N, keyPair[MAX_N * 2];int M, lockKey[MAX_M * 2];bool mark[MAX_M * 2];//for gate i, mark[2i] = true => open lock 2i; mark[2i+1] = true => open lock 2i+1vector<int> out[MAX_M * 2];int stack[MAX_M * 2], cnt;void init(int m){memset(mark, 0, 2*m);for(int i = 2*m-1; i > -1; --i) out[i].clear();}void build(int m){int i, j, a, b;for(i = 0; i < m; ++i){//2i是gate i的第一把锁a = lockKey[2 * i];for(j = i-1; j > -1; --j){//2j是gate j的第一把锁b = lockKey[2 * j];if(b != a && keyPair[b] == keyPair[a]){//lock 2i和lock 2j不能同时开//要是开2i就不能开2j,反之亦然out[2 * i].push_back(2 * j + 1);out[2 * j].push_back(2 * i + 1);}//2j+1是gate j的第二把锁b = lockKey[2 * j + 1];if(b != a && keyPair[b] == keyPair[a]){//lock 2i和lock 2j+1不能同时开//要是开2i就不能开2j+1,反之亦然out[2 * i].push_back(2 * j);out[2 * j + 1].push_back(2 * i + 1);}}//2i+1是gate i的第二把锁a = lockKey[2 * i + 1];for(j = i-1; j > -1; --j){//2j是gate j的第一把锁b = lockKey[2 * j];if(b != a && keyPair[b] == keyPair[a]){//lock 2i+1和lock 2j不能同时开//要是开2i+1就不能开2j,反之亦然out[2 * i + 1].push_back(2 * j + 1);out[2 * j].push_back(2 * i);}//2j+1是gate j的第二把锁b = lockKey[2 * j + 1];if(b != a && keyPair[b] == keyPair[a]){//lock 2i+1和lock 2j+1不能同时开//要是开2i+1就不能开2j+1,反之亦然out[2 * i + 1].push_back(2 * j);out[2 * j + 1].push_back(2 * i);}}}}bool dfs(int x){if(mark[x ^ 1]) return false;if(mark[x]) return true;mark[x] = true;stack[cnt++] = x;vector<int>& v = out[x];for(int i = v.size() - 1; i > -1; --i){if(!dfs(v[i])) return false;}return true;}bool test(int m){init(m);build(m);for(int i = 0; i < m; ++i){cnt = 0;if(!dfs(i << 1)){while(cnt) mark[stack[--cnt]] = false;if(!dfs(i << 1 | 1)) return false;}}return true;}int main(){int i, k, l, m, r;while(scanf("%d%d", &N, &M), N){//inputfor(i = 0; i < N; ++i){scanf("%d%d", &l, &r);keyPair[l] = keyPair[r] = i;}k = 0;for(i = 0; i < M; ++i){scanf("%d%d", lockKey + k, lockKey + k + 1);k += 2;}//binary searchl = 1; r = M + 1;while(l + 1 < r){m = (l + r) >> 1;if(test(m)) l = m;else r = m;}printf("%d\n", l);}return 0;}

0 0
原创粉丝点击